1.什么是缓冲流,有什么作用?
这里需要说明一点小知识,在对硬盘进行读写操作时,一个完整的文件的读写速率要远远高于同样大小的散文件的读写速率。这是因为散文件需要不断地访问、关闭硬盘,极大地浪费了时间,缓冲流也是同样原理。
缓冲流基于IO流,在IO流中使用。顾名思义,它是一个缓冲内存,即在对外部设备中的文件进行读写操作时,先创建一定内存,然后再在这部分内存中读写数据,读写完成后再统一访问该设备。使用缓冲流减少了对外部硬盘的访问次数,通过一系列测试证明,使用缓冲流可成几十倍甚至上百倍地提高读写效率,尤其是对于非文本文件的操作。
【重点】
- 所有的缓冲流都只是提供缓存,没有任何的读取、写入文件能力,需要对应的I、O流来进行输入输出。
- 在创建缓冲流流对象时,需要传入的参数为——对应的输入流对象或输出流对象。
- 底层会提供一个默认大小的缓冲数组,用于提高效率
2.分类
因缓冲流基于IO流,而IO流分别按走向、操作单元可分为输入、输出流,字节、字符流,因此缓冲流也有同样的分类:
字节输入缓冲流: BufferedInputStream
字节输出缓冲流: BufferedOutputStream
字符输入缓冲流: BufferedReader
字符输出缓冲流: BufferedWrite
2.1 字节缓冲流
2.1.1【输入】字节缓冲流
BufferedInputStream(InputStream inputStream);
形参为一个字节输入流基类对象。当然也可以传入InputStream子类对象
【效率问题】
-
1.在BufferedInputStream底层会默认提供一个容量为8KB的byte类型缓冲数组
-
2.fill方法是一个操作核心
a.从硬盘中读取数据,读取的数据容量和缓冲数组容量一致 b.所有的read方法,都是从缓冲数组中读取数据 c.每一次读取数据之前,都会检查缓冲区内是否有数据,如果没有,fill方法执行,填充数据,
-
3.利用缓冲,fill方法,可以极大地降低CPU通过内存访问硬盘的次数,同时程序操作的数据是在内存中进行交互的。
2.1.2【输出】字节缓冲流
BufferedOutputStream(OutputStream outputStream);
形参为一个字节输出流基类对象。也可以传入OutputStream子类对象
【效率问题】
- 1.同BufferedInputStream,默认8kb的byte类型缓冲数组
- 2.写入文件时,同样是先写入内存的8kb缓冲数组中,然后再统一保存到硬盘文件中
- 3.如果默认容量8kb不够用,会直接flush缓冲区,数据保存到硬盘中,同时清空整个缓冲区,重复使用。
- 4.在BufferedOutputStream关闭时,首先会调用flush方法,保存数据到文件,清空缓冲区,并且规划缓冲区占用内存,同时关闭缓冲流使用的字节输出流。
代码演示(拷贝效率)
有缓冲数组的方法:
总耗时1716 ms
public static void useBuffered() {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(new File("D:/aaa/2.txt")));
bos = new BufferedOutputStream(new FileOutputStream(new File("D:/aaa/buffered.txt")));
int content = -1;
while ((content = bis.read()) != -1) {
bos.write(content);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
无缓冲数组的方法:
总耗时531000
public static void copy() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:/aaa/2.txt");
fos = new FileOutputStream("D:/aaa/copy.txt");
int content = -1;
while ((content = fis.read()) != -1) {
fos.write(content);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
2.2字符缓冲流
字符缓冲流基本同于字节缓冲流
输入字符缓冲流: BufferedReader
输出字符缓冲流: BufferedWrite
【注意】
- 1.字符缓冲输入流,底层默认提供一个有8192个元素的缓冲字符数组,而且使用fill方法从硬盘中读取数据填充缓冲数组
- 2.字符缓冲输出流,底层有默认提供一个有8192个元素的缓冲字符数组,使用flush方法将缓冲数组中的内容写入到硬盘当中。
- 3.使用缓冲数组之后,程序在运行的大部分时间内,都是内存和内存之间的数据交互,降低了CPU通过内存操作硬盘的次数,效率高
- 4.关闭字符缓冲流,都会首先释放对应的缓冲数组内存,然后关闭对应的字符输入流、字符输出流。
- 5.字符缓冲输入流中 String readLine(); 读取一行数据
- 6.字符缓冲输出流中 void newLine(); 换行