欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

常用IO类介绍 博客分类: IO io 

程序员文章站 2024-03-16 19:42:52
...
这个博客还没有写完
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();

相关标签: io