JAVA IO中的缓冲流

28 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

缓冲流基本介绍

缓冲流可以提高字节流和字符流的读写数据的性能

缓冲流分为四类:

  • BufferedInputStream:字节缓冲输入流,可以提高字节输入流读数据的性能
  • BufferedOutStream:字节缓冲输出流,可以提高字节输出流写数据的性能
  • BufferedReader:字符缓冲输入流,可以提高字符输入流读数据的性能
  • BufferedWriter:字符缓冲输出流,可以提高字符输出流写数据的性能

字节缓冲输入

字节缓冲输入流:BufferedInputStream

作用:可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道,提高字节输入流读数据的性能

构造器:public BufferedInputStream(InputStream in)

原理:缓冲字节输入流管道自带了一个 8KB 的缓冲池,每次可以直接借用操作系统的功能最多提取 8KB 的数据到缓冲池中去,以后我们直接从缓冲池读取数据,所以性能较好

public class BufferedInputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        // 1.定义一个低级的字节输入流与源文件接通
        InputStream is = new FileInputStream("Demo/src/test.txt");
        // 2.把低级的字节输入流包装成一个高级的缓冲字节输入流。
        BufferInputStream bis = new BufferInputStream(is);
        // 3.定义一个字节数组按照循环读取。
        byte[] buffer = new byte[1024];
        int len;
        while((len = bis.read(buffer)) != -1){
            String rs = new String(buffer, 0 , len);
            System.out.print(rs);
        }
    }
}

字节缓冲输出

字节缓冲输出流:BufferedOutputStream

作用:可以把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能

构造器:public BufferedOutputStream(OutputStream os)

原理:缓冲字节输出流自带了 8KB 缓冲池,数据就直接写入到缓冲池中去,性能提高了

public class BufferedOutputStreamDemo02 {
    public static void main(String[] args) throws Exception {
        // 1.写一个原始的字节输出流
        OutputStream os = new FileOutputStream("Demo/src/test.txt");
        // 2.把低级的字节输出流包装成一个高级的缓冲字节输出流
        BufferedOutputStream bos =  new BufferedOutputStream(os);
        // 3.写数据出去
        bos.write('a');
        bos.write(100);
        bos.write("我爱中国".getBytes());
        bos.close();
    }
}

字节流性能

利用字节流的复制统计各种写法形式下缓冲流的性能执行情况

复制流:

  • 使用低级的字节流按照一个一个字节的形式复制文件
  • 使用低级的字节流按照一个一个字节数组的形式复制文件
  • 使用高级的缓冲字节流按照一个一个字节的形式复制文件
  • 使用高级的缓冲字节流按照一个一个字节数组的形式复制文件

高级的缓冲字节流按照一个一个字节数组的形式复制文件,性能最高,建议使用


字符缓冲输入

字符缓冲输入流:BufferedReader

作用:字符缓冲输入流把字符输入流包装成高级的缓冲字符输入流,可以提高字符输入流读数据的性能。

构造器:public BufferedReader(Reader reader)

原理:缓冲字符输入流默认会有一个 8K 的字符缓冲池,可以提高读字符的性能

按照行读取数据的功能:public String readLine() 读取一行数据返回,读取完毕返回 null

public static void main(String[] args) throws Exception {
    // 1.定义一个原始的字符输入流读取源文件
    Reader fr = new FileReader("Demo/src/test.txt");
    // 2.把低级的字符输入流管道包装成一个高级的缓冲字符输入流管道
    BufferedReader br = new BufferedReader(fr);
    // 定义一个字符串变量存储每行数据
    String line;
    while((line = br.readLine()) != null){
        System.out.println(line);
    }
    br.close();
    //淘汰数组循环读取
    //char[] buffer = new char[1024];
    //int len;
    //while((len = br.read(buffer)) != -1){
    //System.out.println(new String(buffer , 0 , len));
}

字符缓冲输出

符缓冲输出流:BufferedWriter

作用:把低级的字符输出流包装成一个高级的缓冲字符输出流,提高写字符数据的性能。

构造器:public BufferedWriter(Writer writer)

原理:高级的字符缓冲输出流多了一个 8K 的字符缓冲池,写数据性能极大提高了

字符缓冲输出流多了一个换行的特有功能:public void newLine() 新建一行

public static void main(String[] args) throws Exception {
    Writer fw = new FileWriter("Demo/src/test.txt",true);//追加
    BufferedWriter bw = new BufferedWriter(fw);
    
    bw.write("我爱学习Java");
    bw.newLine();//换行
    bw.close();
}

高效原因

字符型缓冲流高效的原因:(空间换时间)

  • BufferedReader:每次调用 read 方法,只有第一次从磁盘中读取了 8192(8k)个字符,存储到该类型对象的缓冲区数组中,将其中一个返回给调用者,再次调用 read 方法时,就不需要访问磁盘,直接从缓冲区中拿出一个数据即可,提升了效率
  • BufferedWriter:每次调用 write 方法,不会直接将字符刷新到文件中,而是存储到字符数组中,等字符数组写满了,才一次性刷新到文件中,减少了和磁盘交互的次数,提升了效率

字节型缓冲流高效的原因:

  • BufferedInputStream:在该类型中准备了一个数组,存储字节信息,当外界调用 read() 方法想获取一个字节的时候,该对象从文件中一次性读取了 8192 个字节到数组中,只返回了第一个字节给调用者。将来调用者再次调用 read 方法时,当前对象就不需要再次访问磁盘,只需要从数组中取出一个字节返回给调用者即可,由于读取的是数组,所以速度非常快。当 8192 个字节全都读取完成之后,再需要读取一个字节,就得让该对象到文件中读取下一个 8192 个字节
  • BufferedOutputStream:在该类型中准备了一个数组,存储字节信息,当外界调用 write 方法想写出一个字节的时候,该对象直接将这个字节存储到了自己的数组中,而不刷新到文件中。一直到该数组所有 8192 个位置全都占满,该对象才把这个数组中的所有数据一次性写出到目标文件中。如果最后一次循环没有将数组写满,最终在关闭流对象的时候,也会将该数组中的数据刷新到文件中。

注意:字节流和字符流,都是装满时自动写出,或者没满时手动 flush 写出,或 close 时刷新写出