IO流(2)-缓冲流

目录

1. 缓冲流的简单介绍

2. 为什么要用到缓冲流

3. 缓冲流是如何提高读写性能的?

3.1 BufferedInputStream 源码

3.2 BufferdOutputStream 源码

3.3 BufferReader 源码

3.4 BufferWriter 源码

4. BufferInputStream和BufferOutputStream

5. BufferedReader 与 BufferedWriter


1. 缓冲流的简单介绍

我们上贴说到了 FileInputStream,FileOutputStream,FileReader,FileWriter。 

其实这四个流,我们通常把它叫做原始流,它们是比较偏底层的;而今天我们要说的四个缓冲流,如下图所示,叫包装流,也叫处理流,它们之间也有继承关系自下而上,并且它们都可以提高原始流读写数据的性能。

IO流(2)-缓冲流_第1张图片

2. 为什么要用到缓冲流

我先来说一下为什么要用到字节缓冲流,我们来看下面这幅图。

现在有一个需求,将D盘下一个大小为 16KB 的文件拷贝到C盘,该怎么做?

如果我们采用原始的字节流或者字符流,我们首先定义一个大小为 1KB 的数组,然后通过输入流读取数据,将数据读取到字节数组中, 然后再使用输出流将数组中的数据写入到C盘,由于数据源大小为16KB,我们输入流需要读取16次,输出流同样也要输出16次,这样合计就是32次,非常消耗系统资源,那么有没有什么更好的解决方案呢,在不改变题目的前提下,让我们减少与磁盘的IO次数,提高程序整体的运行效率呢?

当然是有的,它就是我们接下来要说的缓冲流

IO流(2)-缓冲流_第2张图片

3. 缓冲流是如何提高读写性能的?

IO流(2)-缓冲流_第3张图片

如上图所示,缓冲流之所以能提高读写的性能,是因为如果我们使用缓存输入流,那么它就会在内存中开辟一处大小为8KB输入缓存区,缓存输出流也是同样的道理,它也会在内存中开辟一处大小为8KB的输出缓存区;

还拿刚才的例子来说,当我们读取文件时,这8KB的输入缓存区会直接读满数据源中8KB的资源,然后,我们的缓存输出流在输出时,会从这8KB的缓存区读取内容,读取到内容之后,再写入另外8KB的输出缓冲区,当输出缓存区满了之后,会一次性的将8KB的数据以下次写入硬盘,由于内存中的读写效率非常的高,所以时间可以忽略不计,我们只看从D盘到内存和从内存到C盘的次数.

16KB需要读取两次,也需要输出两次,共计四次。而我们使用之前输入流和输出流,需要读写32次,效率提高了8倍,可以说是极大地提高了读写效率。

我们下面来看一下源码就知道了

3.1 BufferedInputStream 源码

IO流(2)-缓冲流_第4张图片

 上图是 BufferdInputStream 的源码类,这里定义了一个 int变量 大小为 8192,就是1024 * 8IO流(2)-缓冲流_第5张图片

 往下翻可以找到 BufferdInputStream 的构造方法,我们点击 this 查看IO流(2)-缓冲流_第6张图片

 可以看到这里它 new 了一个数组,size 就是我们刚才说的那个 int 值,如此看来就是new 了一个大小为 8KB 的字节数组。

3.2 BufferdOutputStream 源码

IO流(2)-缓冲流_第7张图片

这里也是一样,8192 ,也为8KB,点击this 方法查看如下

IO流(2)-缓冲流_第8张图片

它也是 new 了一个大小为 8KB 的字节数组。

3.3 BufferReader 源码

IO流(2)-缓冲流_第9张图片

 以上即为 BufferdReader 的源码,可以看到它这里也是 new 了一个大小为 8KB 的字符数组

3.4 BufferWriter 源码

IO流(2)-缓冲流_第10张图片

 以上为 BufferdWriter 的源码,也是定义了一个大小为 8BK 的字符数组。

总的来说,缓冲流能提高读写效率的原因,是因为它们会在内存开辟缓存空间,减少了与磁盘的IO次数,从而提高了读写效率。

4. BufferInputStream和BufferOutputStream

BufferdInputStream 和 BufferdOutputStream 的构造器如下所示,它们分别需要传入一个 InputStream 的对象 和 OutputStream 的对象。

IO流(2)-缓冲流_第11张图片

刚才我们看源码也看到了,其实BufferedInputStream还有一个构造方法,我们可以自行传入一个数组的大小,如果不传入,默认为8KB,我们也可以重载该构造方法,自行传入,例如传入一个 1024 * 16 ,那么就是在内存中创建一个 16KB大小的 缓存输入流空间,其它流也是同样的道理。

我做一个简单的案例,还是从C盘拷贝一个文件到D盘,如下代码

public static void main(String[] args) {
        // 创建输入流对象
        InputStream is = null;
        // 创建输出流对象
        OutputStream os = null;
        // 创建字节缓冲输入流对象
        BufferedInputStream bis = null;
        // 创建字节缓冲输出流对象
        BufferedOutputStream bos = null;
        try {
            is = new FileInputStream("user-service/test.txt");
            os = new FileOutputStream("D:/test2.txt");
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(os);
            // 定义一个大小为 1024 的字节数组
            byte[] bytes = new byte[1024];

            // 定义一个长度变量,记录读取到的字节数量
            int length;
            // 定义循环读取文件内容
            while((length = bis.read(bytes)) != -1){
                // 将读取到的内容写入磁盘
                bos.write(bytes,0,length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (bos != null)
                    bos.close();
                if (bis != null)
                    bis.close();
                if (os != null)
                    os.close();
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

运行上述代码,得到如下结果,我们到D盘查看,可以看到拷贝成功

IO流(2)-缓冲流_第12张图片

5. BufferedReader 与 BufferedWriter

BufferedReader 与 BufferedWriter 的构造器根字节缓冲输入流,字节缓冲输出流极其相似,都是要传入一个流对象,这里就不需要我做过多的赘述了,适用语法也半差不差;

在字符缓冲输入流中还新增了一个方法,可以一行一行的读取数据

IO流(2)-缓冲流_第13张图片

在字符缓冲输出流中也新增了一个方法,换行操作

IO流(2)-缓冲流_第14张图片

我们把刚才字节缓冲流的代码稍微改动一下仍然可以用,如下

public static void main(String[] args) {
        // 创建输入流对象
        Reader r = null;
        // 创建输出流对象
        Writer w = null;
        // 创建字节缓冲输入流对象
        BufferedReader br = null;
        // 创建字节缓冲输出流对象
        BufferedWriter bw = null;
        try {
            r = new FileReader("user-service/test.txt");
            w = new FileWriter("D:/test3.txt");
            br = new BufferedReader(r);
            bw = new BufferedWriter(w);
            // 定义一个大小为 1024 的字节数组
            char[] chars = new char[1024];

            // 定义一个长度变量,记录读取到的字节数量
            int length;

            // 定义循环读取文件内容
            while((length = br.read(chars)) != -1){
                // 将读取到的内容写入磁盘
                bw.write(chars,0,length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (bw != null)
                    bw.close();
                if (br != null)
                    br.close();
                if (w != null)
                    w.close();
                if (r != null)
                    r.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

运行上述代码,得到如下结果,到D盘查看,发现存在test3.txt 文件 ,点击查看,文件内容也都开碑过来了,说明代码无误。

IO流(2)-缓冲流_第15张图片

未完待续......

你可能感兴趣的:(spring,java,后端)