IO流
字符流
FileReader 从文件中读取字符
FileWriter 将字符写入到文件中
BufferReader 是Reader的子类,自带缓存空间,存取数据更有效
InputStreamReader 转换流,要搭配使用
BufferdWriter 是writer的子类,自带缓存空间,存取数据更有效
OutputStreamWriter 转换流,要搭配使用
都继承:Read,Writer。
字节流
BufferdInputStream 此类自带缓冲区,以字节的形式读取文件内容
BufferdOutputStream
FileInputStream 此类用于从本地文件读字节流。
FilterInputStream
FileOutputStream 此类用于将字节流写入文件。
FilterOutputStream
都继承:InputStream OutputStream
第一次总结:
1.以reader,writer结尾的都是字符流,以stream结尾的都是字节流。
2.有buffer的都自带缓冲区,便于存取大文件,减少IO操作。
3.带StreamReader和StreamWriter的都是转换流,将字节流转换为字符流,并且能指定字符集
如何使用IO流:网上找到最多的 三种用法。(以写为例)
1.FileWriter与BufferedWriter
单独使用FileWriter时,每写一次就会有一次IO,效率极低
通常用法是:BufferedWriter bw = new BufferedWriter(new FileWriter);
这样,就会添加上了一个缓冲区,每次读取都是从缓冲区读取,提高性能。
2.OutputStreamWriter与FileOutputStream
FileOutputStream是以字节的方式写入文件,而OutputStreamWriter是转换流,
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“E:\utf_8.txt”));
两者结合使用,是将字节传输后,转化为字符流写入到文件中。
3.BufferedWriter与OutputStreamWriter与FileOutputStream
这三种结合使用,在2的基础上添加了一个缓冲区
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“c:/a.txt”,true)))
三者结合使用,是将字节输出后,转化为字符流,再写入到缓冲区,最后写入到文件。
第二次总结:
1.带buffer的,不能单独使用,需要作为缓冲池。
实际应用1:
全程字符流,读取,写入文件:使用
new BufferedWriter(new FileWriter);
new BufferedReader(new FileReader);
其中File*****一定要有,用来打开文件流,
buffer****可以有,也可以没有,用来提高IO效率。
特点:全程字符流
实际应用2:
字节流读取,写入。读取到的数据为字符流。使用:
new BufferedWriter(new OutputStreamWriter(new FileOutputStream())
new BufferedReader(new InputStreamReader(new FileInputStream())
其中File*****Stream一定要有,
转换流*****Stream*****可以有,可以没有,没有的话会出现乱码。(没有测试)
缓冲区Buffered***可以有,可以没有,有的话能提升效率。
特点:文件端字符流,内存端字符流
实际应用3:
全程字节流,读取,写入文件:使用
new BufferInputStream(new FileInputStream())
new BufferOutputStream(new FileOutputStream())
其中File****Stream一定要有
缓冲区Buffer*****Stream可有可无,同1,用作缓冲区提高效率。
(特点:全程字节流,需搭配byte[] bb = new byte[]获取,才会不显示乱码)
代码实现
/**
* 测试字符流读文件
*/
@Test
public void ReadFile_Reader() {
//打开字符流
String s;
try (FileReader fr = new FileReader(tempFile);
BufferedReader br= new BufferedReader(fr)){
while((s=br.readLine())!=null) {
System.out.println(s+"\t");
}
}catch(Exception e) {
throw new RuntimeException("出现读取异常:"+e);
}
}
/**
* 测试字节流转字符流读文件
*/
@Test
public void ReadFile_StreamToReader() {
String s;
try(FileInputStream fds = new FileInputStream(tempFile); //以字节读取文件
InputStreamReader osr = new InputStreamReader(fds,"UTF-8"); //将字节转化为字符,UTF-8编码
BufferedReader br = new BufferedReader(osr)){ //增加缓冲区
while((s=br.readLine())!=null) {
System.out.println(s+"\t");
}
}catch(Exception e) {
throw new RuntimeException("出现读取异常:"+e);
}
}
/**
* 测试字节流读取文件
*/
@Test
public void ReadFile_Stream() {
int point;
/**
* 以字节读取,不支持readline();
* 只能一次读取所有数据,可以借助byte数组,
* 指定byte数组的大小,从而实现分段读取.
*/
try(FileInputStream fis = new FileInputStream(tempFile); //以字节读取文件
BufferedInputStream bis = new BufferedInputStream(fis)){ //添加缓冲区
/**
* 将缓冲区的字节读取到byte中
* 这段语句的意思是:
* 循环将数据读出到buffer中,直到buffer被装满,
* read()方法会返回-1,执行输出语句,
*
* String(buffer)的意思是将整个buffer中的数据都输出,
* byte数组中的元素写入过程是这样的,数据是从前往后依次写入,
* 如果数据量大于byte数组大小时,指针会回到0位置,再写入将会覆盖原有数据。后面的数据还是之前的。
* 所以,但byte数组的大侠设置过小时,不能用String(buffer),
* 得指定输出范围,使用String(buffer,0,point)。
* 当byte[]数组大小,大于数据总量时,就不需要指定输出范围。
*
*/
byte[] buffer = new byte[1024];
while((point=bis.read(buffer))!=-1) {
System.out.print(new String(buffer,0,point));
}
}catch(Exception e) {
throw new RuntimeException("出现读取异常:"+e);
}
}
第三次总结
区别:
1.字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的
2.字节流在操作文件时,即使不关闭资源,也能输出。但是如果字符流不使用Close()方法,则不会输出任何内容。如果需要输出缓冲区的数据,需要用到Flush()函数。但在jdk1.7及之后的版本就不用关注资源的关闭了,jdk1.7及之后的版本提供了try-with-resource语法,整段代码只有try-catch部分的语句,甚至catch部分的语句都不是必须的,在执行完之后,会自动关闭资源。
3、Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1
inputStream的read()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用0-255来表示的值就得用字符流来读取!比如说汉字.
开发中究竟用字节流好还是用字符流好呢?
一、字符(Reader和 Writer):中文,字符是只有在内存中才会形成的,操作字符、字符数组或字符串,
二、字节(InputStream 和OutputStream):音频文件、图片、歌曲,所有的硬盘上保存文件或进行传输的时候,操作字节和字节数组或二进制对象,
*如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。