缓冲流详解

一、概述

缓冲流,也叫高效流,它可以对那些基本的字节字符流进行增强,达到提高数据的读写能力。

二、缓冲流原理

创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

图解:

1

这个就好一个家庭饮水要从自来水厂输送,但是如果他家里有一个水桶的话,在用水的时候直接从这个水桶里取水就会比较快,因为距离比较近(内存里表示读取速度快)

大白话:我们在使用水的时候从水桶取水不是会更快吗?但是所有的水均来自自来水厂(源数据是一样的,管道还是那条输送管道)

2

注意:

  1. 缓冲区不是越大越好的,因为缓冲区占用的是内存,缓冲区过大就会出现内存空间占用严重。
  2. 一般默认的缓冲区为 8M

三、缓冲流分类

因为是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:

  • 字节缓冲流BufferedInputStreamBufferedOutputStream
  • 字符缓冲流BufferedReaderBufferedWriter

四、字节缓冲流

4.1 字节缓冲输出流【BufferedOutputStream】

java.io.BufferedOutputStream extends OutputStream

  • 继承自父类的共性成员方法 :

    • public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
    • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
    • public void write(byte[] b):将 b.length 字节从指定的字节数组写入此输出流。
    • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len 字节,从偏移量 off开始输出到此输出流。
    • public abstract void write(int b) :将指定的字节输出流。
  • 构造方法 :

    • BufferedOutputStrea m(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

    • BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

      • 参数:

        OutputStream out :字节输出流
             我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高 FileOutputStream 的写入效率
        int size :指定缓冲流内部缓冲区的大小,不指定默认

  • 使用步骤(重点)

    1. 创建 FileOutputStream 对象,构造方法中绑定要输出的目的地
    2. 创建 BufferedOutputStream 对象,构造方法中传递 FileOutputStream 对象对象,提高FileOutputStream 对象效率
    3. 使用 BufferedOutputStream 对象中的方法 write ,把数据写入到内部缓冲区中
    4. 使用 BufferedOutputStream 对象中的方法 flush ,把内部缓冲区中的数据,刷新到文件中
    5. 释放资源(会先调用 flush 方法刷新数据,故第4步可以省略)
  • 代码演示

    public class Demo01BufferedOutputStream {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("10_IO\\a.txt");   
            BufferedOutputStream bos = new BufferedOutputStream(fos);
         
            bos.write("我把数据写入到内部缓冲区中".getBytes());
            
            bos.flush();
            bos.close();
        }
    
    }
    

4.2 字节缓冲输入流 【BufferedInputStream】

java.io.BufferedInputStream extends InputStream

  • 继承自父类的成员方法 :

    • public int read() :从输入流中读取数据的下一个字节。
    • public int read(byte[] b):从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
    • public void close() :关闭此输入流并释放与该流关联的所有系统资源。
  • 构造方法 :

    • BufferedInputStream(InputStream in) 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
    • BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
      • 参数:
        InputStream in:字节输入流
             我们可以传递 FileInputStream,缓冲流会给 FileInputStream 增加一个缓冲区,提高 FileInputStream 的读取效率
        int size:指定缓冲流内部缓冲区的大小,不指定默认
  • 使用步骤(重点)

    1. 创建 FileInputStream 对象,构造方法中绑定要读取的数据源
    2. 创建 BufferedInputStream 对象,构造方法中传递 FileInputStream 对象,提高FileInputStream 对象的读取效率
    3. 使用 BufferedInputStream 对象中的方法 read,读取文件
    4. 释放资源
  • 代码演示

    public class Demo02BufferedInputStream {
        public static void main(String[] args) throws IOException {
        
            FileInputStream fis = new FileInputStream("10_IO\\a.txt");
            BufferedInputStream bis = new BufferedInputStream(fis);
            
            //int read()从输入流中读取数据的下一个字节。
            /*int len = 0;//记录每次读取到的字节
            while((len = bis.read())!=-1){
                System.out.println(len);
            }*/
    
            //int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
            byte[] bytes =new byte[1024];//存储每次读取的数据
            int len = 0; //记录每次读取的有效字节个数
            while((len = bis.read(bytes))!=-1){
                System.out.println(new String(bytes,0,len));
            }
    
            bis.close();
        }
    }
    

4.3 练习–效率测试

我们通过复制文件,测试它的效率

基本流

代码如下:

public class Demo01CopyFile {
    public static void main(String[] args) {
        // 记录开始时间
        long s = System.currentTimeMillis();
        try (
                //1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
                FileInputStream fis = new FileInputStream("D:\\1.zip");
                //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
                FileOutputStream fos = new FileOutputStream("E:\\1.zip")
        ) {
            //一次读取一个字节写入一个字节的方式
            //3.使用字节输入流对象中的方法read读取文件
           /* int len = 0;
            while ((len = fis.read()) != -1) {
                //4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
                fos.write(len);
            }*/

            //使用数组缓冲读取多个字节,写入多个字节
            byte[] bytes = new byte[1024];
            //3.使用字节输入流对象中的方法read读取文件
            int len = 0;//每次读取的有效字节个数
            while ((len = fis.read(bytes)) != -1) {
                //4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 记录结束时间
        long e = System.currentTimeMillis();
        System.out.println("复制文件共耗时:" + (e - s) + "毫秒");
    }
}

测试结果:

文件的大小:3.92 MB
一次读写一个字节: 24268 毫秒
使用数组缓冲读取多个字节,写入多个字节: 35 毫秒

缓冲流

代码如下:

public class Demo02CopyFile {
    public static void main(String[] args) throws IOException {
        // 记录开始时间
        long s = System.currentTimeMillis();
        try (
                //1.创建字节缓冲输入流对象,构造方法中传递字节输入流
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\1.zip"));
                //2.创建字节缓冲输出流对象,构造方法中传递字节输出流
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\1.zip"));
        ) {
            //3.使用字节缓冲输入流对象中的方法read,读取文件
            //一次读取一个字节写入一个字节的方式
            /*int len = 0;
            while ((len = bis.read()) != -1) {
                bos.write(len);
            }*/

            //使用数组缓冲读取多个字节,写入多个字节
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }

        }
        // 记录开结束时间
        long e = System.currentTimeMillis();
        System.out.println("复制文件共耗时:" + (e - s) + "毫秒");
    }
}

测试结果:

文件的大小:3.92 MB
一次读写一个字节: 73 毫秒
使用数组缓冲读取多个字节,写入多个字节: 12 毫秒

从以上测试可知,缓冲流明显提高了读写效率。

五、字符缓冲流

5.1 字符缓冲输出流 【BufferedWriter】

java.io.BufferedWriter extends Writer

  • 继承自父类的共性成员方法 :

    • public void write(int c) :写入单个字符。
    • public void write(char[] cbuf) :写入字符数组。
    • public abstract void write(char[] cbuf, int off, int len) :写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
    • public void write(String str) :写入字符串。
    • public void write(String str, int off, int len) :写入字符串的某一部分,off 字符串的开始索引,len 写的字符个数。
    • public void flush() :刷新该流的缓冲。
    • public void close() :关闭此流,但要先刷新它。
  • 构造方法 :

    • BufferedWriter(Writer out) :创建一个使用默认大小输出缓冲区的缓冲字符输出流。
    • BufferedWriter(Writer out, int size) :创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
      • 参数:
        Writer out :字符输出流
            我们可以传递 FileWriter ,缓冲流会给 FileWriter 增加一个缓冲区,提高FileWriter 的写入效率
        int size :指定缓冲区的大小,不写默认大小
  • 特有成员方法

    public void newLine() : 写一行行分隔符,由系统属性定义符号。

    换行:换行符号

        windows :\r\n
        linux :/n
        mac :/r

  • 使用步骤

    1. 创建字符缓冲输出流对象,构造方法中传递字符输出流
    2. 调用字符缓冲输出流中的方法 write ,把数据写入到内存缓冲区中
    3. 调用字符缓冲输出流中的方法 flush ,把内存缓冲区中的数据,刷新到文件中
    4. 释放资源
  • 代码演示

public class Demo03BufferedWriter {
    public static void main(String[] args) throws IOException {
        
        BufferedWriter bw = new BufferedWriter(new FileWriter("10_IO\\c.txt"));
        
        for (int i = 0; i <10 ; i++) {
            bw.write("Java程序员");
            //bw.write("\r\n");
            bw.newLine();
        }
        
        bw.flush();
        bw.close();
    }
}

5.2 字符缓冲输入流 【BufferedReader】

java.io.BufferedReader extends Reader

  • 继承自父类的共性成员方法 :

    • public int read() :读取单个字符并返回。
    • public int read(char[] cbuf) :一次读取多个字符,将字符读入数组。
    • public void close() :关闭该流并释放与之关联的所有资源。
  • 构造方法 :

    • BufferedReader(Reader in) :创建一个使用默认大小输入缓冲区的缓冲字符输入流。

    • BufferedReader(Reader in, int size) :创建一个使用指定大小输入缓冲区的缓冲字符输入流。

      • 参数:
        Reader in :字符输入流
            我们可以传递 FileReader ,缓冲流会给 FileReader 增加一个缓冲区,提高FileReader 的读取效率

        int size :指定缓冲区的大小,不写默认大小

  • 特有成员方法

    public String readLine() :读取一个文本行。读取一行数据

    • 行的终止符号:

      通过下列字符之一即可认为某行已终止:换行 ( \n )、回车 ( \r ) 或回车后直接跟着换行 ( \r\n )。

    • 返回值 :
      包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

  • 使用步骤 :

    1. 创建字符缓冲输入流对象,构造方法中传递字符输入流
    2. 使用字符缓冲输入流对象中的方法 read/readLine 读取文本
    3. 释放资源
  • 代码演示

    public class Demo04BufferedReader {
        public static void main(String[] args) throws IOException {
           
            BufferedReader br = new BufferedReader(new FileReader("10_IO\\c.txt"));
    
            String line;
            while((line = br.readLine())!=null){
                System.out.println(line);
            }
    
            br.close();
        }
    }
    

5.3 练习–文本排序

请将文本信息恢复顺序。按照(1,2,3…)顺序排序

2.云蜷缩着它鼓鼓的身体,荡漾在空中。
1.我望了望窗外,一个太阳偷笑的日子。
4.所谓惆怅,突然被一声蝉鸣湮没。----《蝉禅》
3.我来不及把一季的幻想甩开,风来不及把潮湿的雨季吹干,鸟来不及把春天的故事唱完,夏天的馥郁就与我邂逅了。

案例分析

  1. 逐行读取文本信息。
  2. 解析文本信息到集合中。
  3. 遍历集合,按顺序,写出文本信息。

案例实现

public class Demo05Test {
    public static void main(String[] args) throws IOException {
        //1.创建一个HashMap集合对象,可以:存储每行文本的序号(1,2,3,..);value:存储每行的文本
        HashMap<String,String> map = new HashMap<>();
        //2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
        BufferedReader br = new BufferedReader(new FileReader("10_IO\\in.txt"));
        //3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
        BufferedWriter bw = new BufferedWriter(new FileWriter("10_IO\\out.txt"));
        //4.使用字符缓冲输入流中的方法readline,逐行读取文本
        String line;
        while((line = br.readLine())!=null){
            //5.对读取到的文本进行切割,获取行中的序号和文本内容
            String[] arr = line.split("\\.");
            //6.把切割好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3,4..)
            map.put(arr[0],arr[1]);
        }

        //7.遍历HashMap集合,获取每一个键值对
        for(String key : map.keySet()){
            String value = map.get(key);
            //8.把每一个键值对,拼接为一个文本行
            line = key + "." + value;
            //9.把拼接好的文本,使用字符缓冲输出流中的方法write,写入到文件中
            bw.write(line);
            bw.newLine();//写换行
        }
        //10.释放资源
        bw.close();
        br.close();
    }
}

结果

1.我望了望窗外,一个太阳偷笑的日子。
2.云蜷缩着它鼓鼓的身体,荡漾在空中。
3.我来不及把一季的幻想甩开,风来不及把潮湿的雨季吹干,鸟来不及把春天的故事唱完,夏天的馥郁就与我邂逅了。
4.所谓惆怅,突然被一声蝉鸣湮没。----《蝉禅》
  • 9
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江七7

感谢大佬的赏赐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值