常用IO类介绍

这个博客还没有写完
java中的流按类型可分为字节流和字符流,按流向分可分为输入流和输出流,这里按字节流和字符流来讲解.
字符流有两个基类: Reader 和 Writer
字节流有两个基类: InputStream 和 OutputStream

字节流用来读写图片,视频,音频,zip,rar,pdf,word....等非纯文字的文件.
字符流用来读写txt,java,html,xml....等纯文字(可用文本编辑器打开)的文件

不论什么文件,在硬盘上存储的都是0和1排列组合的二进制数据,为什么文本能够被txt打开成文字显示,那都是因为我们用软件对这个二进制数据进行了翻译,即解码, 我们通过文本编辑器来录入文字,会读取这些0和1然后查GBK或UTF-8等等码表解码得到对应的文字展示给我们, 播放器也是读到0和1然后去查一个颜色表(我是这样想的),根据0和1不同的排列组合显示不同的颜色,这些颜色拼接起来就成了图像....
我们也可以用播放器强行去解码txt文件(把txt文件对应的0和1去查颜色表),只不过解出来可能是一些奇怪的颜色,
我们也可以用txt编辑器去解码视频(把视频的0和1去查GBK等码表),只不过显示出来是乱码
,为了便于区分哪个文件去查哪中表解码, 给文件加上了各种扩展名,而不论什么文件, 本质都是0和1,那么读写文件用字节流就够了,就是把0和1这样的文件进行读写嘛,那为什么要有字符流呢?
好, 假设有个文本文件, 内容是 "我是IO流", 存到硬盘上后假设是
0100 1111 1010 1010 .......
这时,我要你读取这个文件中的第一个字即"我", 那你一次性要读到这个二进制数据的第几位?我们都知道GBK码表中,一个汉字是两个字节,那么要读取"我"时,应该读两个字节,当读到I和O时,由于英文字母只占1个字节,所以应该读1个字节然后查表,所以如果你用字节流来读文字,那么你得自己判断读几个后去查表,而字符流确屏蔽了这些,它一次读取一个字符,所以不论这个字占几个字节,字符流都能完整的读取这个字(我说的仅仅是读取文本中的某些字,并不是复制这个文本,复制根本不用管一个字占几个字节,直接把这些0和1照着来一份就行了).

一, 字符流
用字符流操作文本文件,一般用其子类FileWriter,FileReader比较方便

1.1 写文本文件的操作
FileWriter fw = new FileWriter("D:/a.txt");
fw.close();

上述代码,不论D:/a.txt存不存在,都会创建一个空的a.txt,所以当D:/a.txt存在并且有内容,a.txt会被清空

FileWriter fw = new FileWriter("D:/a.txt",true);
fw.write("我是IO流");
fw.close();

上述代码,若D:/a.txt不存在,会创建一个空的a.txt,若a.txt存在那么不会清空a.txt中的内容, 而是在a.txt的末尾继续写入.

close() 和 flush() 方法的区别?
close()方法用于关闭流, 但在关闭流之前, 会做一次flush()方法的功能,将内存中缓存的数据写出,然后才关闭流,流被关闭后就不可以用这个流再进行读写操作.
flush()方法用于将内存中缓存的数据写出, 但不会关闭流, 还可以用继续使用这个流
FileWriter fw = new FileWriter("D:/a.txt",true);
fw.write("我很好\r\n");//这个数据实际上还在内存中
fw.flush();//将内存中的数据刷到了硬盘上,内存被清空
fw.write("我是IO流");//又向内存中写入了数据
fw.close();//流被关闭,但在关闭前,将内存中的数据刷到了硬盘上

fw.write("我被关闭了,我还想写");//这句执行时报错了

报错如下:
Exception in thread "main" java.io.IOException: Stream closed
	at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:135)
	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:220)
	at java.io.Writer.write(Writer.java:157)
	at io.reader_writer.WriterDemo1.main(WriterDemo1.java:19)



1.2 读文本的操作
读取D:/a.txt中的第一个字符, a.txt的内容是 "我是IO流"
                //打印机器目前默认的码表
		System.out.println(System.getProperty("file.encoding"));//我这里输出是UTF-8
		
		FileReader fr = new FileReader("D:/a.txt");
		int i = fr.read();
		System.out.println(i);//25105,化成16进制就是6211,可查附件utf-8码表,得到正好是"我"
		System.out.println((char)i);//我,将25105按utf-8码表解码成字符
		fr.close();


此代码只读取a.txt中的第一个字符, 即 "我" , 虽然在GBK(当前操作系统默认的)码表中,"我" 占2个字节, 但是也是一个字符, 如果这里用字节流读取,会发生什么现象?
将25105化成二进制是0110 0010 0001 0001,2个字节,16个bit位,
字符流一次性将这两个字节读取然后查表得到"我"
字节流呢?一次读一个字节,如果读一个字节即0110 0010后就查表,那肯定不是乱码就是错误的字,所以字节流得判断一次读几个字节去查表,好麻烦的....

1.3 无缓冲读取整个文件中的内容并打印
FileReader fr = new FileReader("D:/a.txt");
int i = 0;
while((i=fr.read())!=-1){
	System.out.print((char)i);
}
fr.close();

字符流的read()方法,一次读取一个字符,返回该字符对应的码表值,读取一个字符后,指针向下移动一个字符,再次读取时就读到下一个字符,指针不能回退,一直移动到文件末尾会返回-1,利用这些特性就可以用上面循环的方式读取一个文件.
read()方法一次读一个字符


1.4 有缓冲区的读取文件
FileReader fr = new FileReader("D:/a.txt");
char[] buff = new char[4];
int i = 0;
while((i=fr.read(buff))!=-1){
	System.out.print(new String(buff,0,i));
}
fr.close();


定义了一个长度为4的字符数组作为缓冲区,read(char[])方法会挨个读取字符,将字符存入到数组中,注意:
调用一次read(char[]),会读取4个字符,并不是只读一个字符,也就是一次read(char[])相当于执行4次read()方法
所以如果一个文件中内容为"abcdef",用上述代码读取,第一次会读取abcd,返回4,表示读到了4个字符
第二次会读取ef,返回2,表示读到了2个字符,但这时数组内容为efcd(用ef覆盖了前面的ab),所以在转为字符串的时候,只能使用new String(buff,0,i)-----表示读到了几个字符就将几个字符转成字符串,防止最后一次读取未装满数组而导致错数据
那么读取abcdef请问这个while循环会执行多少次?
2次
第一次读abcd
第二次读ef
第三次读到-1退出循环(这次循环条件执行了,循环体未执行)

1.5 字符流BufferedReader 和 BufferedWriter
它们在构造时接收一个字符流对象进行包装,用来增强字符流功能.
上面看到字符流可以自定义一个缓冲区(字符数组),为了使用更方便,java提供了本身就具有缓冲功能的BufferedXxxx ,它们默认缓冲大小是8kb,即8192(源码中就是这么写的), 这个大小也可以自己定义,它们提供了2种构造,其中一种构造就可以指定缓冲大小.
除了我们可以不用定义缓冲区,它还提供了readLine()功能,一次读取一行文字
FileReader fr = new FileReader("D:/a.txt");
BufferedReader br = new BufferedReader(fr,1024);//包装FileReader,同时自定义缓冲区大小为1024
String str = null;
while((str=br.readLine())!=null){
	System.out.print(str);
}
fr.close();
br.close();


FileWriter fw = new FileWriter("D:/a.txt");
		BufferedWriter bw = new BufferedWriter(fw,1024);
		String str = "我要把数据写到文件中去";
		bw.write(str);
		bw.newLine();//换行
		bw.write("继续写");
		//fw.close();//这句不用写,写了会报错.BufferedWriter会自动关闭FileWriter
		bw.close();

猜你喜欢

转载自18810098265.iteye.com/blog/2208439
今日推荐