1.缓冲流概述
- 包装流
IO流根据功能花划分,可以分为:节点流和包装流(处理流)。
节点流: 可以从或向一个特定的地方(节点)读写数据,例如:FileOutputStream、FileInputStream、FileWriter和FileReader等。
包装流:对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写,例如:缓冲流、转换流和合并流等。
- 缓冲流
在我们学习字节流与字符流的时候,大家都进行过读取文件中数据的操作,读取数据量大的文件时,读取的速度会很慢,很影响我们程序的效率,那么我想提高效率,怎么办呢?
那么可以使用缓冲流进行文件读取操作,缓冲流是一个包装流,目的是缓存作用,加快读取和写入数据的速度。
字节缓冲流:BufferedInputStream、BufferedOutputStream
字符缓冲流:BufferedReader、BufferedWriter
注意:缓冲流属于包装流,只能对已有的流进行封装,不能直接关联文件进行操作
- 缓冲流原理
原理:先把数据先写入缓冲区,等缓冲区满了,再把数据写到文件里。
在JVM中会开辟一块缓冲区的内存空间,然后将文件中的数据读取到缓冲区中,直到读满这个缓冲,才会将缓冲区中的数据获取到程序中。
在JVM中会开辟一块缓冲区的内存空间,然后将程序中的数据写入到缓冲区中,直到写满这个缓冲,才会将缓冲区中的数据写入到文件中。
比如说,家里盖房子,有一堆砖头要搬在工地100米外,单字节的读取就好比你一个人每次搬一块砖头,从堆砖头的地方搬到工地,这样肯定效率低下。然而聪明的人类会用小推车,每次先搬砖头搬到小车上,再利用小推车运到工地上去,这样你再从小推车上取砖头是不是方便多了呀!这样效率就会大大提高,缓冲流就好比我们的小推车,给数据暂时提供一个可存放的空间。
总结:缓冲流直接内存中读取数据的方式要比每次都访问磁盘的效率高很多,所以缓冲流的读取效率高。
2.字节缓冲流
字节缓冲流根据流的方向,共有 2 个:
-
写入数据到流中,字节缓冲输出流 BufferedOutputStream
-
读取流中的数据,字节缓冲输入流 BufferedInputStream
它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了 IO 流的读写速度。
2.1 BufferedOutputStream类
BufferedOutputStream类从FilterOutputStream类继承而来,FilterOutputStream类继承于OutputStream类。
-
构造方法
从构造方法中我们可以知道BufferedOutputStream没有无参构造方法,它必须传入一个OutputStream (一般是FileOutputStream)来一起使用。另外,我们还可以指定缓冲区的大小,一般情况下,使用默认的缓冲区大小就足够了(默认大小为8192)。 -
常用的方法
字节输出缓冲流(BufferedOutputStream)没有声明字节任何新的方法,它只是覆盖了基类的方法。
关于flush()方法使用场景:
假设一个文件有1122个字节,缓冲区大小为100个字节,那么要读取12次,最后一次只有22个字节,但此时缓冲区并没有存满,不能将存储的内容从缓冲区中取出。这时我们需要调用缓冲流自带的一个方法flush(强制写入)将最后一次读取的内容强制写入到文件中去。
- 向文件中写出数据
【示例】使用字节缓冲流向文件中写数据
public class BufferedByteDemo {
public static void main(String[] args) throws IOException {
// 指定目的地
FileOutputStream fos = new FileOutputStream("test.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 存数据
bos.write("whsxt".getBytes());
// 刷新数据
bos.flush();
// 关闭流
bos.close();
}
}
关闭缓冲流的时候,我们查看API底层源码,可知:
-
关闭缓冲流的时候,默认先调用flash()方法,然后再去做关闭流的操作。
-
关闭缓冲流的方法时,方法内部已经实现对字节流的关闭,所以此处我们只需要关闭缓冲流即可。
2.2 BufferedInputStream类
BufferedInputStream类从FilterInputStream类继承而来,FilterInputStream类继承于InputStream类。
- 构造方法
从构造方法中我们可以知道BufferedInputStream没有无参构造方法,它必须传入一个InputStream (一般是FileInputStream)来一起使用。另外,我们还可以指定缓冲区的大小,一般情况下,使用默认的缓冲区大小就足够了(默认大小为8192)。
- 常用的方法
字节输入缓冲流(BufferedInputStream)没有声明字节任何新的方法,它只是覆盖了基类的方法。
- 从文件中读入数据
【示例】使用字节缓冲流从文件中读数据
public class BufferedByteDemo {
public static void main(String[] args) throws IOException {
// 指定目的地
FileInputStream fis = new FileInputStream("test.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
int len = 0;
byte[] by = new byte[1024];
StringBuilder sb = new StringBuilder();
// 取数据
while((len = bis.read(by)) != -1) {
sb.append(new String(by, 0, len));
}
System.out.println(sb);
// 关闭流
bis.close();
}
}
我们查看API底层源码,可知:调用关闭缓冲流的方法时,方法内部已经实现对字节流的关闭,所以此处我们只需要关闭缓冲流即可。
2.3字节缓冲流拷贝案例
【示例】字节缓冲流拷贝案例
public class BufferedByteDemo {
public static void main(String[] args) throws IOException {
// 指定数据源
FileInputStream fis = new FileInputStream("E:\\资料\\战狼2.avi");
BufferedInputStream bis = new BufferedInputStream(fis);
// 指定目的地
FileOutputStream fos = new FileOutputStream("E:\\ 战狼2.avi");
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 读数据
byte[] by = new byte[1024];
int len = 0;
while((len = bis.read(by)) != -1) {
// 存数据
bos.write(by, 0, len);
// 刷新数据
bos.flush();
}
// 关闭流
bis.close();
bos.close();
}
}
思考:使用【节点流】和【缓冲流】分别实现文件的拷贝操作,感受两者的工作效率差别。
ps:如需最新的免费文档资料和教学视频,请添加QQ群(627407545)领取。