------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
六、IO
1. IO(Input,Output)流概述
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作分为两种:字节流和字符流
流按流向分为:输入流,输出流
字节流的抽象基类:InputStream,OutputStream
字符流的抽象基类:Reader,Writer
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream
如:Reader的子类FileReader
2. FileWriter
字符流和字节流
字节流两个基类
InputStream OutputStream
字符流两个基类:
Reader,Writer
先学习一下字符流的特点
既然IO流是用于操作数据的
那么数据的最常见的体现形式是:文件。
那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象,FileWriter,后缀名为父类名
前缀名是该流对象的功能
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个FileWriter对象,该对象一被初始化就必须明确被操作的文件
//而且该文件会创建到指定目录下。如果该目录下已有同名文件将被覆盖。
//其实该步就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt");
//调用write方法将字符串写入到流当中
fw.write("abcde");
//刷新流对象中的缓冲中的数据
//将数据刷到目的地中
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部缓冲中的数据。
//将数据刷到目的地中
//和flush区别:flush刷新后,流可以继续使用,close关闭之后,会将流关闭
fw.close();
}
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
FileWriter异常处理
/*
IO异常的处理方式
*/
import java.io.*;
class FileWriterDemo2
{
public static void main(String[] args)
{ FileWriter fw = null;
try
{
fw = new FileWriter("e:\\demo.txt");
fw.write("abcdefg");
}
catch (IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if (fw!=null)
fw.close();
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
}
}
/*
演示对已有文件的续写
*/
import java.io.*;
class FileWriterDemo4
{
public static void main(String[] args) throws IOException
{
//传递一个true参数代表不覆盖已有的文件,并在已有文件末尾处进行数据续写
FileWriter fw = new FileWriter("demo.txt",true);
fw.write("haha\r\nxiexieixieikjhskdjha");
fw.close();
}
}
3. FileReader
注:异常只能try不能抛,此处为求简单抛了异常
第一种读取方式:read()方法
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throws IOException
{ //创建一个文件读取流文件,和指定名称的文件相关联
//要保证该文件是存在的,如果不存在,会发生FileNotFoundException
FileReader fr = new FileReader("demo.txt");
//调用读取流read方法。
//read方法一次读一个字符而且会自动往下读
int ch = 0;
while ((ch=fr.read())!=-1)
{
System.out.print((char)ch);
}
/*while(true)
{
int ch1 = fr.read();
if (ch ==-1)
break;
System.out.println((char)ch1);
}
*/
fr.close();
}
}
第二种读取方式:read(char[])方法
/*
第二种方式:通过字符数组进行读取
*/
import java.io.*;
class FileReaderDemo2
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("demo.txt");
//定义一个1024字节(2kb空间大小)的char类型数组
//read(char[])方法返回的是读到的字符个数
char[] buf = new char[1024];
int num = 0;
while ((num=fr.read(buf))!=-1)
{
sop(num+new String(buf,0,num));
}
fr.close();
}
public static void sop(Object obj)
{
System.out.print(obj);
}
}
两种读取方式测试
import java.io.*;
class FileReaderTest
{
public static void main(String[] args) throws IOException
{
method_1();
//1方法较慢
method_2();
//2方法较快
}
public static void method_1() throws IOException
{
FileReader fr = new FileReader("demo.txt");
int num = 0;
while ((num = fr.read())!=-1)
{
sop((char)num);
}
fr.close();
}
public static void method_2() throws IOException
{
FileReader fr = new FileReader("demo.txt");
int num = 0;
char[] ch = new char[1024];
while ((num=fr.read(ch))!=-1)
{
sop(new String(ch,0,num));
}
fr.close();
}
public static void sop(Object obj)
{
System.out.print(obj);
}
}
文件存储练习
/*
将c盘的一个文本文件复制到d盘
复制的原理
其实就是将c盘的下的文件数据存储到d盘的文件中
*/
import java.io.*;
class FileTest
{
public static void main(String[] args) throws IOException
{
method_1();
method_3();
}
public static void method_1() throws IOException
{
FileReader fr = new FileReader("demo.txt");
int num = 0;
char[] ch = new char[1024];
while ((num=fr.read(ch))!=-1)
{
method_2(num,ch);
}
fr.close();
}
public static void method_2(int num,char...ch) throws IOException
{
FileWriter fw = new FileWriter("d:\\demo.txt",true);
fw.write(ch,0,num);
fw.flush();
fw.close();
}
public static void method_3() throws IOException
{
FileReader fr = new FileReader("d:\\demo.txt");
int num = 0;
char[] ch = new char[1024];
while ((num=fr.read(ch))!=-1)
{
sop(new String(ch,0,num));
}
fr.close();
sop("复制成功!!!!!!!!!!!!!");
}
public static void sop(Object obj)
{
System.out.print(obj);
}
}
4. 字符输入流缓冲区应用:BufferedWriter
/*
缓冲区的出现是为了提高流的操作效率二出现的
所以在创建缓冲区之前,必须要先有流对象
该缓冲区中提供了一个跨平台的换行符
newLine()方法
*/
import java.io.*;
class BufferedWriterDemo
{
public static void main(String[] args)
{ FileWriter fw = null;
BufferedWriter bufw = null;
try
{
fw = new FileWriter("buf.txt");
//为了提高字符写入流效率,加入了缓冲技术
//只要将需要被提高的流对象作为参数传递给缓冲区的构造函数即可
bufw = new BufferedWriter(fw);
bufw.write("abcdeasdasdasdasd");
bufw.newLine();
//记住,只要用到缓冲区,就要记得刷新。
bufw.flush();
}
catch (IOException e)
{
throw new RuntimeException(e.toString());
}
finally
{
try
{
if (fw!=null)
//其实关闭缓冲区就是关闭缓冲区中的流对象
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException(e.toString());
}
}
}
}
5. 字符读取流缓冲区应用:BufferedReader
字符读取流缓冲区:
*/
import java.io.*;
class BufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("demo.txt");
//为提高效率加入缓冲技术,将字符读取流对象对象作为参数传递给缓冲对象的构造函数
BufferedReader br = new BufferedReader(fr);
String s1 =null;
while ((s1= br.readLine())!=null)
{
sop(s1);
}
br.close();
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
6. 通过缓冲区复制文本文件
/*
通过缓冲区复制一个文件
*/
import java.io.*;
class CopyBufferedDemo
{
public static void main(String[] args)
{
BufferedReader br = null;
BufferedWriter bw = null;
try
{
br = new BufferedReader(new FileReader("demo.txt"));
bw = new BufferedWriter(new FileWriter("e:\\demo.txt"));
String line = null;
while ((line=br.readLine())!=null)
{
bw.write(line);
bw.newLine();
}
}
catch (IOException e)
{
throw new RuntimeException(e.toString());
}
finally
{
try
{
if(br!=null && bw!=null)
{
br.close();
bw.close();
}
}
catch (IOException e)
{
throw new RuntimeException(e.toString());
}
}
}
}
7. 装饰设计模式
/*
装饰设计模式
增强一个类功能
先自定义类,将原有对象传入,基于已有功能,并提供加强功能
那么自定义的该类称为装饰类
装饰类通常会通过构造方法接收被装饰的对象并基于被装饰对象的功能提供更强的功能
*/
class Person
{
public void chifan()
{
System.out.println("吃饭");
}
}
class SuperPerson
{
private Person p;
SuperPerson(Person p)
{
this.p = p;
}
public void chifan()
{
p.chifan();
System.out.println("吃饭1");
System.out.println("吃饭2");
System.out.println("吃饭3");
}
}
class PersonDemo
{
public static void main(String[] args)
{
SuperPerson p = new SuperPerson(new Person());
p.chifan();
}
}
8. LineNumberReader
带行号打印的字符流对象LineNumberReader(继承与BufferedReader)主要有setLineNumber(int),getLineNumber()两个方法设置和获取行号
import java.io.*;
class LineNumberReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("demo.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(100);
while ((line=lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber()+":"+line);
}
}
}
9. InputStream OutputStream
/*
字符流
FileReader
FileWriter
BufferedReader
BufferedWriter
字节流
InputStream OutputStream
需求,想要操作图片数据。这是就要用到字节流。
*/
import java.io.*;
class Demo1
{
public static void main(String[] args) throws IOException
{
readFile_4();
}
public static void readFile_4() throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int num = fis.available();//此方法慎用,用于数据不是太大的时候
byte[] by = new byte[num];
fis.read(by);
sop(new String(by,0,num));
fis.close();
}
public static void readFile_3() throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int num = fis.available();
sop(num);
fis.close();
}
public static void readFile_2() throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int num = 0;
byte[] by = new byte[1024];
while ((num=fis.read(by))!=-1)
{
sop(new String(by,0,num));
}
fis.close();
}
public static void readFile_1() throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int ch = 0;
while ((ch = fis.read())!=-1)
{
sop((char)ch);
}
fis.close();
}
public static void writeFile() throws IOException
{
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("absfsdf".getBytes());
//字节流在没有缓冲区的情况下不需要刷新
fos.close();
}
public static void sop(Object o)
{
System.out.println(o);
}
}
10. 通过缓冲区使用字节流复制Mp3文件
/*
演示mp3的复制,通过缓冲区
BufferedOutputStream
BufferedInputStream
*/
import java.io.*;
class CopyMp3
{
public static void main(String[] args) throws IOException
{
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
sop((end-start)+"毫秒"); }
//通过字节流的缓冲区完成复制
public static void copy_1() throws IOException
{
BufferedInputStream bufis =
new BufferedInputStream(new FileInputStream("e:\\50道JAVA基础编程练习题.zip"));
BufferedOutputStream bufos =
new BufferedOutputStream(new FileOutputStream("e:\\111.rar"));
int by = 0;
while ((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufis.close();
bufos.close();
}
public static void sop(Object o)
{
System.out.println(o);
}
}
11. 读取键盘录入
/*
读取键盘录入
System.out:对应的是标准的输出设备,控制台
System.in:标准的输入设备:键盘
需求:
通过键盘录入数据
当录入一行数据后,就将该行数据进行打印
如果录入的数据是over,那么停止录入
*/
import java.io.*;
class ReadIn
{
public static void main(String[] args) throws IOException
{
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while (true)
{
int ch = in.read();
if(ch=='\r')
continue;
if(ch=='\n')
{
String s = sb.toString();
if("over".equals(s)||"OVER".equals(s))
break;
sop(s.toUpperCase());
sop(s.toLowerCase());
sb.delete(0,sb.length());
}
else
sb.append((char)ch);
}
}
public static void sop(Object o)
{
System.out.println(o);
}
}
<pre class="java" name="code"> InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
BufferedReader bufr = new BufferedReader(isr);
三句话可以简写为:
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in))
读取键盘录入
12. 字节流字符流的转换流
/*
通过上面的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理
也就是readLine方法
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是BufferedReader类的方法
而键盘录入的read方法是InputStream的方法。
那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?
InputStreamReader 是字节流通向字符流的桥梁:
它使用指定的 charset 读取字节并将其解码为字符。
它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:
BufferedReader in
= new BufferedReader(new InputStreamReader(System.in));
*/
import java.io.*;
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
InputStream in = System.in;
//将字节流转换成字符流对象,使用转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,使用字符缓冲区技术,BufferedReader
BufferedReader bufr = new BufferedReader(isr);
String line = null;
/* while ((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
sop(line.toUpperCase());
}*/
//将字节流的写入流转换为字符流写入流,OutputStreamWriter
//OutputStreamWriter 是字符流通向字节流的桥梁
/* 可使用指定的 charset 将要写入流中的字符编码成字节。
它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。
在写入底层输出流之前,得到的这些字节将在缓冲区中累积。
可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。
注意,传递给 write() 方法的字符没有缓冲。
为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,
以避免频繁调用转换器。例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
*/
OutputStream os =System.out;
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bufw = new BufferedWriter(osw);
String s = null;
while ((s=bufr.readLine())!=null)
{
if ("over".equals(s))
break;
bufw.write(s.toUpperCase());
bufw.newLine();
//写入流需要flush()方法刷新一下缓冲区
bufw.flush();
}
bufr.close();
bufw.close();
}
public static void sop(Object o)
{
System.out.println(o);
}
}
13. 键盘录入存储文件练习
/*
需求:把键盘录入的数据存储到一个文件中
*/
import java.io.*;
class SystemInTest
{
public static void main(String[] args) throws IOException
{
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("FileWriter.txt",true))));
String line = null;
while ((line=bfr.readLine())!=null)
{
if("over".equals(line))
break;
bw.write(line);
bw.newLine();
bw.flush();
}
bfr.close();
bw.close();
}
}
14. 读取文件输出到控制台
/*
需求:想要将文件数据打印在控制台上
*/
import java.io.*;
class SystemOutTest
{
public static void main(String[] args) throws IOException
{
BufferedReader br =
new BufferedReader (new InputStreamReader(new FileInputStream("FileWriter.txt")));
BufferedWriter bw = new BufferedWriter (new OutputStreamWriter(System.out));
String line = null;
while ((line=br.readLine())!=null)
{
if("over".equals(line))
break;
bw.write(line);
bw.newLine();
bw.flush();
}
}
}
15. 流操作的基本规律
1,明确源和目的
源:输入流 InputStream和Reader
目的:输出流 OutputStream和Writer
2,操作的数据是否是纯文本
是:字符流
不是:字节流
3,当体系明确后,再明确要使用那个具体对象
通过设备来进行区分
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
1,将一个文本文件中的数据存储到另一个文件中,复制文件
源:因为是源,所以使用读取流。InputStream Reader
是不是操作文本文件
是,这是可以选择reader
这样体系就明确了
接下来明确要使用体系中的那个对象
明确设备:硬盘上的一个文件
Reader体系中可以操作文件的对象时FileReader
目的:OutputStream Writer
是否为纯文本
是,Writer
设备:硬盘,一个文件
Writer体系中可以操作文件的对象是FileReader
2,将图片数据存储到另一个文件中,复制文件
源:因为是源,所以使用读取流。InputStream Reader
是不是操作文本文件
不是,这是可以选择InputStream
这样体系就明确了
接下来明确要使用体系中的那个对象
明确设备:硬盘上的一个文件
InputStream体系中可以操作文件的对象时FileInputStream
目的:OutputStream Writer
是否为纯文本
不是,OutputStream
设备:硬盘,一个文件
OutputStream体系中可以操作文件的对象是FileOutputStream
3,将键盘录入保存到文件中
键盘录入:字节读取流转为读取转换流再转为字符读取流再转为字符读取缓冲区
4,将文件内容输出到控制台
输出控制台:字节写入流转为写入转换流再转为字符写入流再转为字符写入缓冲区
16. 转换流应用
可以将录入的数据转换为指定的编码表(utf-8),将数据存到文件中
OutputStreamWriter osw = OutputStreamWriter(new FileOutputStream(“d.txt”),”utf-8”);
所以,转换流什么时候使用呢?字符与字节之间的桥梁,通常涉及到字符编码转换时需要用到转换流
17. File对象
/*
File类的常见方法:
1,创建
boolean createNewFile();
在指定位置创建文件,如果该文件已经存在,则不创建,返回false
和输出流不一样,输出流对象一建立就创建文件,文件存在就覆盖
boolean mkdir();创建文件夹,只能创建一级目录,如果该文件夹存在,返回false
boolean mkdirs();创建多级文件夹
2,删除
boolean delete();删除失败返回false
void deleteOnExit();程序退出时删除指定文件
3,判断
boolean canExecute();能否被执行
boolean exists();是否存在
isFile();
isDirectory();
f.isHidden();
f.isAbsolute()
4,获取信息
getName()
getPath()
getPArent()
getAbsolute()
long length()
long lastModified()
renameTo() //重命名
*/
import java.io.*;
class FileDemo
{
public static void main(String[] args) throws IOException
{
method_1();
}
public static void method_1() throws IOException
{
File f = new File("c:\\AAAAAAA\\demo.txt");
File f1 = new File("c:\\AAAAAAA\\huanghai");
File f2 = new File("c:"+File.separator+"abc"+File.separator+"b.txt");
sop("f----"+f);
//f.deleteOnExit(); //void返回类型,在退出时删除此文件
sop("f1----"+f1);
sop("f2----"+f2);
//在判断文件对象是否是文件或者目录是,必须要先判断该文件对象封装的内容是否存在。
//通过exists判断
sop("f1.mkdir()----"+f1.mkdir());//创建文件夹
sop("f.canExecute()----"+f.canExecute());//判断文件能否被执行
sop("f.createNewFile()----"+f.createNewFile());//创建文件
sop("f.exists()----"+f.exists());//******判断文件是否存在
sop("f.getPath()----"+f.getPath());//将此抽象路径名转换为一个路径名字符串。
sop("f.isAbsolute()"+f.isAbsolute());//是否为绝对路径
sop("f.length()----"+f.length());//long返回类型,返回文件大小
sop("f.canRead()----"+f.canRead());//测试应用程序是否可以读取此抽象路径名表示的文件。
sop("f.getTotalSpace()----"+f.getTotalSpace());//返回此抽象路径名指定的分区大小
sop("f.getParentFile()----"+f.getParentFile());//返回此抽象路径名父目录的抽象路径名
//在判断文件是否是目录或者是文件时,首先必须判断是否存在 exists();
sop("f.isDirectory()----"+f.isDirectory());//*********是否是一个目录。
sop("f.isHidden()----"+f.isHidden());//是否是一个隐藏文件。
sop("f.isFile()----"+f.isFile());//**********是否是一个标准文件。
//sop("f.delete()----"+f.delete());//删除文件
}
/*
f----c:\AAAAAAA\demo.txt
f1----c:\AAAAAAA\huanghai
f2----c:\abc\b.txt
f1.mkdir()----false
f.canExecute()----false
f.createNewFile()----true
f.exists()----true
f.getPath()----c:\AAAAAAA\demo.txt
f.isAbsolute()true
f.length()----0
f.canRead()----true
f.getTotalSpace()----31864700928
f.getParentFile()----c:\AAAAAAA
f.isDirectory()----false
f.isHidden()----false
f.isFile()----true
*/
public static void sop(Object obj)
{
System.out.println(obj);
}
}
18. 文件名读取练习
import java.io.*;
class FileDemo2
{
public static void main(String[] args)
{
File dir = new File("c:\\");
File[] files = dir.listFiles();
for (File f:files )
{
System.out.println(f.getName()+"---"+f.length());
}
}
public static void listDemo_2()
{
File dir = new File("C:\\Users\\Administrator\\Desktop\\java笔记");
String[] arr = dir.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
//System.out.println(dir+"...."+name);
// if(name.endsWith(".java"))
// return true;
//return false;
return name.endsWith(".java");
}
});
System.out.println(arr.length);
for (String name: arr )
{
System.out.println(name);
}
}
public static void listDemo()
{
File f = new File("c:\\");
String[] names = f.list();
for (String name : names )
{
System.out.println(name);
}
}
public static void listRootsDemo()
{
File[] files = File.listRoots();
for(File f : files)
{
System.out.println(f.length());
}
}
}
19. 递归
/*
***************递归***************
列出指定目录下文件或者文件夹,包含子目录中的内容。
也就是列出指定目录下的所有内容。
因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可
在列出过程中出现的还是目录的话,还可以再次调用本功能
也就是函数自身调用自身
这种表现形式,或者编程手法称为递归
递归要注意:
1,限定条件.
2.注意递归次数,尽量避免内存溢出
*/
import java.io.*;
import java.util.*;
class DiGui
{
public static void main(String[] args)
{
File dir = new File("F:\\BaiduYunDownload");
showDir(dir,1);
// Scanner sc = new Scanner(System.in);
// System.out.print("请输入一个十进制整数:");
// int num = sc.nextInt();
// System.out.println(num+"的二进制表现形式为:");
// toBin(num);
}
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
for (int x=0;x<level ;x++ )
{
sb.append("|--");
}
return sb.toString();
}
public static void showDir(File dir,int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for (int x=0;x<files.length ;x++ )
{
System.out.println(dir);
if (files[x].isDirectory())
{
showDir(files[x],level);
}
else
System.out.println(getLevel(level)+files[x]+"------"+files[x].length());
}
}
//累加
public static int getSum(int n)
{
if(n==1)
return 1;
return n+getSum(n-1);
}
public static void toBin(int num)
{
if(num>0)
{
toBin(num/2);
System.out.print(num%2);
}
}
}
20. [递归]兔子编程题
/*
题目:古典问题:有一对兔子,
从出生后第3个月起每个月都生一对兔子,
小兔子长到第四个月后每个月又生一对兔子,
假如兔子都不死,问每个月的兔子总数为多少?
*/
import java.util.*;
public class tuziwenti {
public static int RabbitNum(int n)
{
//从第3项开始,每一项都等于前两项的和,所以return RabbitNum(n-1)+RabbitNum(n-2)
if(n>2)
{
return RabbitNum(n-1)+RabbitNum(n-2);
}
//单递归到n<2,返回1
return 1;
}
public static void main(String[] args)
{
//定义变量n代表想要求得项数
int n=0;
System.out.println("输入你想求得项数:");
//从键盘录入n
Scanner input=new Scanner(System.in);
n=input.nextInt();
System.out.println("结果是:"+RabbitNum(n));
}
}
21. 练习:删除目录
/*
删除一个带有内容的目录
删除原理
在windows中,删除目录是从里面往外删除的。
既然是从里往外删除,就需要用到递归
*/
import java.io.*;
class ShanChuMuLU
{
public static void main(String[] args)
{
File dir = new File("F:\\BaiduYunDownload");
removeDir(dir);
}
public static void removeDir(File dir)
{
File[] files = dir.listFiles();
for (int x=0;x<files.length ;x++ )
{
if (files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString()+"....."+files[x].delete());
}
System.out.println(dir+"......"+dir.delete());
}
}
22. 练习:将文件路径存储
/*
练习
将一个指定目录下的java文件的绝对路径,存储到一个文本文件中
建立一个java文件列表文件。
思路
1,对指定目录进行递归。
2,获取递归过程中所有的java文件路径
3,将这些路径存到集合当中。
4,将集合中的数据写入到文件中。
*/
import java.util.*;
import java.io.*;
class JavaFileList
{ public static TreeSet<String> ts = new TreeSet<String>();
public static void main(String[] args) throws IOException
{
File dir = new File("C:\\Users\\Administrator\\Desktop\\java笔记");
diGui(dir);
File f = new File("C:\\Users\\Administrator\\Desktop\\文件名数据存储.txt");
f.createNewFile();
FileWriter fw = new FileWriter("C:\\Users\\Administrator\\Desktop\\文件名数据存储.txt");
BufferedWriter bw = new BufferedWriter(fw);
for(String s : ts)
{
bw.write(s);
bw.newLine();
}
bw.flush();
bw.close();
}
public static void diGui(File dir)
{
File[] files = dir.listFiles();
for (File file:files)
{
if(file.isDirectory())
diGui(file);
else
{
if (file.getName().endsWith(".java"))
cunChu(file.getAbsolutePath());
}
}
}
public static void cunChu(String s)
{
ts.add(s);
}
public static void sop(Object o)
{
System.out.println(o);
}
}
23. Properties
Properties:是hastable的子类,存储键值信息,可与IO联系,当存储配置文件时,可以用到它,主要方法有:
String getProperty(String key)
用指定的键在此属性列表中搜索属性。
void list(PrintStream out)
将属性列表输出到指定的输出流。
void list(PrintWriter out)
将属性列表输出到指定的输出流。
void load(InputStream inStream)
从输入流中读取属性列表(键和元素对)。
void load(Reader reader)
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
void loadFromXML(InputStream in)
将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中。
Object setProperty(String key, String value)
调用 Hashtable 的方法 put。
void store(OutputStream out, String comments)
以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,
将此 Properties 表中的属性列表(键和元素对)写入输出流。
void store(Writer writer, String comments)
以适合使用 load(Reader) 方法的格式,
将此 Properties 表中的属性列表(键和元素对)写入输出字符。
void storeToXML(OutputStream os, String comment)
发出一个表示此表中包含的所有属性的 XML 文档。
void storeToXML(OutputStream os, String comment, String encoding)
使用指定的编码发出一个表示此表中包含的所有属性的 XML 文档。
Set<String> stringPropertyNames()
返回此属性列表中的键集,其中该键及其对应值是字符串,
如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
import java.io.*;
import java.util.*;
class lianxi
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("E:\\demo.txt");
Properties pro = new Properties();
pro.load(fr);
pro.list(System.out);
}
}
/*
用于记录应用程序运行次数
*/
import java.io.*;
import java.util.*;
class lianxi1
{
public static void main(String[] args) throws IOException
{
File f = new File("e:\\peizhi.txt");
Properties pro = new Properties();
FileInputStream fis=null;
FileOutputStream fos=null;
if (f.createNewFile())
{
fos= new FileOutputStream("e:\\peizhi.txt",true);
fos.write("count=1".getBytes());
System.out.println("ssssssss");
fos.flush();
fos.close();
}
else
{
fis = new FileInputStream("e:\\peizhi.txt");
pro.load(fis);
System.out.println(pro.getProperty("count"));
int x = Integer.parseInt(pro.getProperty("count"));
pro.setProperty("count",String.valueOf(x+1));
fos= new FileOutputStream("e:\\peizhi.txt");
pro.store(fos,"asdasdasd");
fis.close();
}
}
}
24. 打印流PrintStream
/*
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接受的参数类型
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流
PrintWriter
构造函数可以接受的参数类型
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer
*/
import java.io.*;
class PrintDemo
{
public static void main(String[] args)
{
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("a.txt")));
String line =null;
while (line=bufr.readLine()!=null)
{
out.println(line.toUpperCase());
out.flush();
}
out.close();
bufr.close();
}
}
import java.io.*;
import java.util.*;
class lianxi
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("E:\\demo.txt");
Properties pro = new Properties();
pro.load(fr);
pro.list(System.out);
}
}
String getProperty(String key)
用指定的键在此属性列表中搜索属性。
void list(PrintStream out)
将属性列表输出到指定的输出流。
void list(PrintWriter out)
将属性列表输出到指定的输出流。
void load(InputStream inStream)
从输入流中读取属性列表(键和元素对)。
void load(Reader reader)
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
void loadFromXML(InputStream in)
将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中。
Object setProperty(String key, String value)
调用 Hashtable 的方法 put。
void store(OutputStream out, String comments)
以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,
将此 Properties 表中的属性列表(键和元素对)写入输出流。
void store(Writer writer, String comments)
以适合使用 load(Reader) 方法的格式,
将此 Properties 表中的属性列表(键和元素对)写入输出字符。
void storeToXML(OutputStream os, String comment)
发出一个表示此表中包含的所有属性的 XML 文档。
void storeToXML(OutputStream os, String comment, String encoding)
使用指定的编码发出一个表示此表中包含的所有属性的 XML 文档。
Set<String> stringPropertyNames()
返回此属性列表中的键集,其中该键及其对应值是字符串,
如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
25. 合并流
import java.io.*;
import java.util.*;
class SequenceDemo
{
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
FileInputStream fis1 = new FileInputStream("e:\\1.txt");
FileInputStream fis2 = new FileInputStream("e:\\2.txt");
FileInputStream fis3 = new FileInputStream("e:\\3.txt");
v.add(fis1);
v.add(fis2);
v.add(fis3);
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("e:\\4.txt");
byte[] buf = new byte[1024];
int len = 0;
while ((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
26. Vector方法回顾
Vector集合方法
boolean add(E e)
将指定元素添加到此向量的末尾。
void add(int index, E element)
在此向量的指定位置插入指定的元素。
boolean addAll(Collection<? extends E> c)
将指定 Collection 中的所有元素添加到此向量的末尾,按照指定 collection 的迭代器所返回的顺序添加这些元素。
boolean addAll(int index, Collection<? extends E> c)
在指定位置将指定 Collection 中的所有元素插入到此向量中。
void addElement(E obj)
将指定的组件添加到此向量的末尾,将其大小增加 1。
int capacity()
返回此向量的当前容量。
void clear()
从此向量中移除所有元素。
Object clone()
返回向量的一个副本。
boolean contains(Object o)
如果此向量包含指定的元素,则返回 true。
boolean containsAll(Collection<?> c)
如果此向量包含指定 Collection 中的所有元素,则返回 true。
void copyInto(Object[] anArray)
将此向量的组件复制到指定的数组中。
E elementAt(int index)
返回指定索引处的组件。
Enumeration<E> elements()
返回此向量的组件的枚举。
void ensureCapacity(int minCapacity)
增加此向量的容量(如有必要),以确保其至少能够保存最小容量参数指定的组件数。
boolean equals(Object o)
比较指定对象与此向量的相等性。
E firstElement()
返回此向量的第一个组件(位于索引 0) 处的项)。
E get(int index)
返回向量中指定位置的元素。
int hashCode()
返回此向量的哈希码值。
int indexOf(Object o)
返回此向量中第一次出现的指定元素的索引,如果此向量不包含该元素,则返回 -1。
int indexOf(Object o, int index)
返回此向量中第一次出现的指定元素的索引,从 index 处正向搜索,如果未找到该元素,则返回 -1。
void insertElementAt(E obj, int index)
将指定对象作为此向量中的组件插入到指定的 index 处。
boolean isEmpty()
测试此向量是否不包含组件。
E lastElement()
返回此向量的最后一个组件。
int lastIndexOf(Object o)
返回此向量中最后一次出现的指定元素的索引;如果此向量不包含该元素,则返回 -1。
int lastIndexOf(Object o, int index)
返回此向量中最后一次出现的指定元素的索引,从 index 处逆向搜索,如果未找到该元素,则返回 -1。
E remove(int index)
移除此向量中指定位置的元素。
boolean remove(Object o)
移除此向量中指定元素的第一个匹配项,如果向量不包含该元素,则元素保持不变。
boolean removeAll(Collection<?> c)
从此向量中移除包含在指定 Collection 中的所有元素。
void removeAllElements()
从此向量中移除全部组件,并将其大小设置为零。
boolean removeElement(Object obj)
从此向量中移除变量的第一个(索引最小的)匹配项。
void removeElementAt(int index)
删除指定索引处的组件。
protected void removeRange(int fromIndex, int toIndex)
从此 List 中移除其索引位于 fromIndex(包括)与 toIndex(不包括)之间的所有元素。
boolean retainAll(Collection<?> c)
在此向量中仅保留包含在指定 Collection 中的元素。
E set(int index, E element)
用指定的元素替换此向量中指定位置处的元素。
void setElementAt(E obj, int index)
将此向量指定 index 处的组件设置为指定的对象。
void setSize(int newSize)
设置此向量的大小。
int size()
返回此向量中的组件数。
List<E> subList(int fromIndex, int toIndex)
返回此 List 的部分视图,元素范围为从 fromIndex(包括)到 toIndex(不包括)。
Object[] toArray()
返回一个数组,包含此向量中以恰当顺序存放的所有元素。
<T> T[]
toArray(T[] a)
返回一个数组,包含此向量中以恰当顺序存放的所有元素;返回数组的运行时类型为指定数组的类型。
String toString()
返回此向量的字符串表示形式,其中包含每个元素的 String 表示形式。
void trimToSize()
对此向量的容量进行微调,使其等于向量的当前大小。
27. 切割文件
import java.io.*;
import java.util.*;
class SplitFile
{
public static void main(String[] args) throws IOException
{
//splitFile();
merge();
}
public static void splitFile() throws IOException
{
FileInputStream fis = new FileInputStream("e:\\qq.png");
FileOutputStream fos = null;
byte[] buf = new byte[1024*40];
int len = 0;
int count = 1;
while ((len=fis.read(buf))!=-1)
{
fos = new FileOutputStream("e:\\1\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
public static void merge() throws IOException
{
int count = 1;
ArrayList<FileInputStream> a = new ArrayList<FileInputStream>();
FileOutputStream fos = new FileOutputStream("e:\\1\\hh.png");
while (count<4)
{
a.add(new FileInputStream("e:\\1\\"+(count++)+".part"));
}
final Iterator<FileInputStream> it = a.iterator();
Enumeration<FileInputStream> en =new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
int len = 0;
byte[] buf = new byte[1024*1024];
while ((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
28. 对象流:将对象持久化(存到文件)
import java.io.*;
class ObjectStreamDemo
{
public static void main(String[] args) throws Exception
{
System.out.println("Hello World!");
}
public static void readObj() throws Exception
{
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("obj.txt"))
Person p = (Person)ois.readObject();
p.getName();
p.getAge();
}
public static void writeObj() throws Exception//将对象存起来
{
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("list",39));
oos.close();
}
}
29. 管道流PipedStream
import java.io.*;
class PipedStreamDemo
{
public static void main(String[] args)
{
Read r = new Read();
Write w = new Write();
PipedInputStream in = new PipedInputStream();
PipedOutputStream in = new PipedOutputStream();
in.connect(out);
new Thread(r).start();
new Thread(w).start();
}
}
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream i)
{
this.in = in;
}
public void run()
{
try
{
byte[] buf = new bute[1024];
int len = in.read(buf);
String s = new String(buf,0,len);
System.out.println(s);
in.close();
}
catch ()
{
throw new RuntimeException
}
}
}
class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try
{
out.write("piped lai la".getBytes());
out.close();
}
catch ()
{
throw new RuntimeException("管道输出流失败");
}
}
}
30. 类 RandomAccessFile
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,则抛出 EOFException(是一种 IOException)。如果由于某些原因无法读取任何字节,而不是在读取所需数量的字节之前已到达文件末尾,则抛出 IOException,而不是 EOFException。需要特别指出的是,如果流已被关闭,则可能抛出 IOException。
/*
随机读写访问:多线程下载会用到
该类不算是IO体系中的子类,而是直接继承自Object。
但是它是IO包中的成员,因为它具备读和写的功能
内部封装了一个数组,而且通过指针对数组的元素进行操作
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针的位置
其实完成读写的原理就是内部封装了字节输入流和输出流
通过构造函数可以看出该类只能操作文件。
而且操作文件还有模式:只读r,读写rw
如果模式为只读r,不会创建文件,会去读取一个一个文件,如果该文件不存在,则会报异常。
如果模式为只读rw而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在不会覆盖。
*/
class RandomAccessFileDemo
{
public static void main(String[] args)
{
writeFile();
System.out.println(Integer.toBinaryString(258));
}
public static void readFile()
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
//调整指针
raf.seek(8);
//跳过指定字节数
raf.skipByte(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println("name="+name);
System.out.println("age="+age);
}
public static void writeFile_2()
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8*0);
raf.write("周期".getBytes());
raf.writeInt(52);
}
public static void writeFile()
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getByte());
raf.writeInt(97);
raf.write("王五".getByte());
raf.writeInt(99);
raf.close();
}
}
31. DataInputStream和DataOutputStream
import java.io.*;
/*
可以用于操作基本数据类型的数据的流对象
*/
class DataStreamDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
public static void writeData()
{
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(234.234);
dos.close();
}
public static void readFile()
{
DataInputStream dis =
new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
boolean b = dis.readBoolean();
boolean b = dis.readDouble();
dis.close();
}
public static void writeUTFDemo()
{
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeUTF("你好");
dos.close();
}
public static void readUTFDemo()
{
DataInputStream dis =
new DataInputStream(new FileInputStream("utfdata.txt"));
String s = dis.readUTF();
dis.close();
}
}
32. ByteArrayStream
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
/*
用于操作字节数组的流对象。
ByteArrayInputStream:在构造时,需要接收数据,而且数据源是一个字节数组
ByteArrayInputStream:在构造时,不用自定义数据目的,因为该对象已经内部封装了可变长度的字节数组
这就是数据的目的地
因为两个流对象都操作的数组,并没有使用系统资源
所以,不用进行close()关闭
在流操作规律讲解时:
源设备
键盘System.in 硬盘 FileStream 内存 ArrayStream
目的设备
控制台 System.out 硬盘FileStream 内存 ArrayStream
用流的读写思想来操作数组
*/
class ByteArrayStream
{
public static void main(String[] args)
{
//数据源
ByteArrayInputStream bis = new ByteArrayInputStream("adsdjhaskksh".getBytes());
//明确数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int by =0;
while ((by=bis.read())!=-1)
{
bos.write(by);
}
sop(bos.toString());
sop(bos.size());
}
public static void sop(Object o)
{
System.out.println(o);
}
}
33. 字符编码
import java.io.*;
class BianMa
{
public static void main(String[] args)
{
writeText();
readText();
}
public static void readText()
{
InputStreamReader isr =
new InputStreamReader(new FileInputStream("gbk.txt"),"UTF-8");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
public static void writeText()
{
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("gbk.txt"),"UTF-8");
osw.write("你好");
osw.close();
}
}
34. 练习:将学生信息存到文件中并按总成绩排序
import java.io.*;
import java.util.*;
class StudentChenji
{
public static void main(String[] args) throws IOException
{
TreeSet<Student> ts = new TreeSet<Student>(new StuComparator());
for (int x=0;x<5 ;x++ )
{
Scanner sc = new Scanner(System.in);
sop("请输入第"+(x+1)+"名学生的姓名:");
String name = sc.next();
sop("请输入此同学的语文成绩:");
int yuwen = sc.nextInt();
sop("请输入此同学的数学成绩:");
int shuxue = sc.nextInt();
sop("请输入此同学的英语成绩:");
int yingyu = sc.nextInt();
int sum = yuwen+shuxue+yingyu;
Student s = new Student(name,yuwen,shuxue,yingyu);
ts.add(s);
}
Iterator<Student> it =ts.iterator();
while (it.hasNext())
{
Student s =(Student)it.next();
sop(s.getName());
sop(s.getSum());
}
writeFile(ts);
}
public static void writeFile(TreeSet<Student> ts) throws IOException
{
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("gbk.txt"),"GBK");
Iterator<Student> it =ts.iterator();
while (it.hasNext())
{
Student s =(Student)it.next();
osw.write(s.getName()+" "
+String.valueOf(s.getYuwen())+" "
+String.valueOf(s.getShuxue())+" "
+String.valueOf(s.getYingyu())+" "
+String.valueOf(s.getSum()));
osw.write("\r\n");
osw.flush();
}
osw.close();
}
public static void sop(Object o)
{
System.out.println(o);
}
}
class Student
{
String name;
int yuwen;
int shuxue;
int yingyu;
Student(String name,int yuwen,int shuxue,int yingyu)
{
this.name = name;
this.yuwen = yuwen;
this.shuxue = shuxue;
this.yingyu = yingyu;
}
public int getSum()
{
return yuwen+shuxue+yingyu;
}
public int getYuwen()
{
return yuwen;
}
public int getShuxue()
{
return shuxue;
}
public int getYingyu()
{
return yingyu;
}
public String getName()
{
return name;
}
}
class StuComparator implements Comparator<Student>
{
public int compare(Student s2,Student s1)
{
if(s1.getSum()>s2.getSum())
return 1;
if(s1.getSum()==s2.getSum())
return 0;
return -1;
}
}