zoukankan      html  css  js  c++  java
  • 缓冲流

    缓冲流

    学习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流。比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,就像穿上铠甲的武士一样,相当于是对基本流对象的一种增强。

    1.1 概述

    缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:

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

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

    1.2 字节缓冲

    字节缓冲输出流

    java.io.BufferedOutputStream extends OutputStream

    BufferedOutputStream:字节缓冲输出流

    继承自父类的共性方法:

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

    构造方法

    • BufferedOutputStream(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 static void main(String[] args) throws IOException {
            //  1. 创建FileOutputStream对象,构造方法中绑定要输入的目的地
            FileOutputStream fos = new FileOutputStream("D:\Test\g.txt");
            //  2. 创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            // 3. 使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区
            bos.write("把数据写到缓冲区".getBytes());
            // getBytes():把字符串转换为字节数组
            //  4. 使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
            bos.flush();
            //  5. 释放资源(会先调用flush方法刷新数据,第4部可以省略)
             bos.close();
        }
    

    字节缓冲输入流

    BufferedInputStream:字节缓冲输入流

    java.io.BufferedInputStream extends InputStream

    继承父类的成员方法

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

    构造方法

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

    使用步骤(重点)

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

    示例代码

    public static void main(String[] args) throws IOException {
            // 1. 创建FileInputStream对象,构造方法中绑定要读取的数据源
            FileInputStream fis = new FileInputStream("D:\Test\g.txt");
            // 2. 创建BuffreedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
            BufferedInputStream bis = new BufferedInputStream(fis);
            // 3. 使用BufferedInputStream对象中的方法read,读取文件
    
            // int read() 从输入流中读取数据的下一个字节
            /*int len = 0;
            // 记录读取到的有效字节个数
            while ((len = bis.read())!=-1){
                System.out.println(len);
            }*/
            // int read(byte[] b)  从输入流中读取一定数量的字节,并将其存储在缓冲区b中
            // 记录每次读取到的有效字节
            int len = 0;
            // 存储每次读取到的数据
            byte[] bytes = new byte[1024];
            while ((len = bis.read(bytes))!=-1){
                System.out.println(new String(bytes,0,len));
            }
                     bis.close();
    
        }
    

    效率测试

    查询API,缓冲流读写方法与基本的流是一致的,我们通过复制文件,测试它的效率。

    基本流

    代码如下

    public static void main(String[] args) throws IOException {
            long s = System.currentTimeMillis();
            // 1. 创建一个字节输入流对象,构造方法中绑定要读取的数据源
            FileInputStream fis = new FileInputStream("c:\Test\1.jpg");
            // 2. 创建一个字节输出流对象,构造方法中绑定要写入的目的地
            FileOutputStream fos = new FileOutputStream("d:\Test\1.jpg");
            // 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){
                fos.write(bytes,0,len);
            }
            // 每次读取字节的个数
    
            // 5. 释放资源(先关写的,后关读的,如果写完了,肯定读取完毕了)
            fos.close();
            fis.close();
            long e = System.currentTimeMillis();
            System.out.println("程序运行时间:"+(e-s)+"毫秒");
    
        }
    }
    // 运行结果
    文件大小:2,629,730 字节
    使用字节输入输出流耗时:14179毫秒
    添加个数组  使用字节输入输出流耗时:74毫秒
    

    缓冲流

    代码如下

    public static void main(String[] args) throws IOException {
            long s = System.currentTimeMillis();
            // 创建字节缓冲输入流对象
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\Test\1.jpg"));
            // 创建字节缓冲输出流对象
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\Test\1.jpg"));
            /*// 使用字节输入流的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);
            }
            bos.close();
            bis.close();
            long t = System.currentTimeMillis();
            System.out.println("复制耗费的时间:"+(t-s)+"毫秒");
        }
    }
    // 运行结果
     文件大小:2,629,730 字节
     使用字节缓冲输入输出流耗时:155毫秒
     添加个数组  使用字节缓冲输入输出流耗时:8毫秒
    

    1.3 字符缓冲流

    构造方法

    • public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
    • public BufferedWriter(Writer out): 创建一个新的缓冲输出流。

    构造举例,代码如下:

    // 创建字符缓冲输入流
    BufferedReader br = new BufferedReader(new FileReader("br.txt"));
    // 创建字符缓冲输出流
    BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
    

    特有方法

    字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。

    • BufferedReader:public String readLine(): 读一行文字。
    • BufferedWriter:public void newLine(): 写一行行分隔符,由系统属性定义符号。

    readLine方法演示,代码如下:

    public class BufferedReaderDemo {
        public static void main(String[] args) throws IOException {
          	 // 创建流对象
            BufferedReader br = new BufferedReader(new FileReader("in.txt"));
    		// 定义字符串,保存读取的一行文字
            String line  = null;
          	// 循环读取,读取到最后返回null
            while ((line = br.readLine())!=null) {
                System.out.print(line);
                System.out.println("------");
            }
    		// 释放资源
            br.close();
        }
    }
    

    newLine方法演示,代码如下:

    public class BufferedWriterDemo throws IOException {
        public static void main(String[] args) throws IOException  {
          	// 创建流对象
    		BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
          	// 写出数据
            bw.write("黑马");
          	// 写出换行
            bw.newLine();
            bw.write("程序");
            bw.newLine();
            bw.write("员");
            bw.newLine();
    		// 释放资源
            bw.close();
        }
    }
    输出效果:
    黑马
    程序
    员
    

    1.4 练习:文本排序

    请将文本信息恢复顺序。

    3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
    8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
    4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
    2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
    1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
    9.今当远离,临表涕零,不知所言。
    6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
    7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
    5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
    

    案例分析

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

    案例实现

    public class BufferedTest {
        public static void main(String[] args) throws IOException {
            // 创建map集合,保存文本数据,键为序号,值为文字
            HashMap<String, String> lineMap = new HashMap<>();
    
            // 创建流对象
            BufferedReader br = new BufferedReader(new FileReader("in.txt"));
            BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
    
            // 读取数据
            String line  = null;
            while ((line = br.readLine())!=null) {
                // 解析文本
                String[] split = line.split("\.");
                // 保存到集合
                lineMap.put(split[0],split[1]);
            }
            // 释放资源
            br.close();
    
            // 遍历map集合
            for (int i = 1; i <= lineMap.size(); i++) {
                String key = String.valueOf(i);
                // 获取map中文本
                String value = lineMap.get(key);
              	// 写出拼接文本
                bw.write(key+"."+value);
              	// 写出换行
                bw.newLine();
            }
    		// 释放资源
            bw.close();
        }
    }
    
  • 相关阅读:
    测试方案
    测试需求
    软件测试知识点总结
    自动化测试
    测试——缺陷报告包括那些内容,由什么组成
    测试——缺陷的类型
    软件测试工具简介
    测试工程师
    剑指offer系列21--二叉搜索树的后续遍历序列
    剑指offer系列20--从上到下打印二叉树
  • 原文地址:https://www.cnblogs.com/anke-z/p/12697066.html
Copyright © 2011-2022 走看看