zoukankan      html  css  js  c++  java
  • IO 流之字符流的缓冲区

    1. 缓冲区的出现提高了对数据的读写效率
    2. 对应类:
      1. BufferedWriter
      2. BufferedReader
    3. 缓冲区需要结合流才可以使用, 对流的功能进行了增强, 即对流的操作起到装饰作用

    使用缓冲区实现文本文件的写入和读取

    // 写入
    public class BufferedWriterDemo{
        public static void main(String[] args) throws IOException {
    
            FileWriter fw = new FileWriter("buf.txt");
    
            // 为了提高写入的效率, 使用了字符流的缓冲区
            // 创建了一个字符写入流的缓冲对象, 并和指定要被缓冲的流对象相关联
    
            BufferedWriter bufw = new BufferedWriter(fw);
    
            // 使用缓冲区的写入方法将数据写入到缓冲区中
            bufw.write("abcde");
    
            // 换行, 其实就是封装了系统属性  line.separator
            // BufferedWriter 特有方法
            bufw.newLine();
    
            bufw.newline("hahaha");
    
            // 使用缓冲区的刷新方法将数据刷入到目的地中
            bufw.flush();
    
            // 关闭缓冲区, 其实关闭的就是被缓冲的流对象
            bufw.close();
        }
    }
    
    // 读取
    public class BufferedReaderDemo {
        public static void main(String[] args){
    
            FileReader fr = new FileReader("buf.txt");
            BufferedReader bufr = new BufferedReader();
    
            /*  读取字符数组的方式
             *
             *  char[] buf = new char[1024];
    
             *  int len = 0;
             *  while((len=bufr.read(buf))!= -1){
             *  System.out.println(new String(buf,0,len));
             *  }
             */
    
             // 按一行读取, BufferredReader 特有方法: readLine()
             // 如果到达流末尾, 返回 null
             String line = null;
             while((line=bufr.readLine()) != null){  // 注意: 此处判断的是 != null
                System.out.println(line);
            }
    
            // 关闭缓冲区
            bufr.close();
        }
    }
    

    BufferedReader 中的 readLine() 方法原理

    • BufferedReader 类复写了父类的以下方法:
      • read(); : 读取单个字符
      • read(char[] buf, int off, int len); : 读取数组的一部分
    • BufferedReader 类自己特有的方法 readLine()
    • BufferedReader 类继承了父类方法:
      • read(char[] buf) : 将字符读入数组

    readLine() 方法原理: 使用了读取缓冲区的 read() 方法, 将读取到的字符进行缓冲并判断换行标记. 将标记前的缓存数据变成字符返回.

    模拟实现 BufferedReader

    // 需求: 自定义的读取缓冲区, 其实就是模拟一个 BufferedReader
    
    /* 分析:
     *    缓冲区中无非就是封装了一个数组, 并对外提供了更多的方法对数组进行访问
     *    其实这些方法最终操作的都是数组的角标
     *
     *     缓冲区原理: 其实就是从源中获取一批数据装进缓冲区中, 在从缓冲区中不断
     *     的取出一个一个数据.
     *     
     *     在缓冲区中数据此次取完后, 在从源中继续取一批数据进缓冲区, 当源中的数据取光时,
     *     用 -1 作为结束标记
     */
    
     public class MyBufferedReader{
    
        private FileReader r;
    
        // 定义一个数组作为缓冲区
        private char[] buf = new char[1024];
    
        // 定义一个指针用于操作这个数组中的元素, 当操作到最后一个元素时, 指针应该归 0
        private int pos = 0;
    
        // 定义一个计数器, 记录缓冲区中的数据个数. 当该数据减到0, 就从源中继续获取数据到缓冲区中
        private int count = 0;
    
        // 带参数的构造函数, 指定增强的流对象
        public MyBufferedReader(FileReader r){
            this.r = r;
        }
    
        // 定义从缓冲区读取单个字符的 read() 方法
        public int myRead() throws IOException{
    
            // 1. 从源中获取一批数据到缓冲区中, 需要先做判断, 只有计数器为 0 时, 才需要从源中获取数据
            /* if(count == 0){
    
             *   // 记录从源中获取的数据个数
             *   count = r.read(buf);
    
             *   if(count < 0){
             *      return -1;
             *  }
    
             *  // 每次从源中获取数据到缓冲区后, 角标归零
             *   pos = 0;
    
             *   // 获取第一个数据
             *   char ch = buf[pos];
    
             *   pos++;
             *   count--;
    
             *   return ch;
             *   } else {
    
             *   char ch = buf[pos];
    
             *   pos++;
             *   count--;
    
             *   return ch;
             *   }
             */
            // 代码优化:
    
            if(count == 0){
                count = r.read(buf);
    
                pos = 0;
            }
    
            if(count < 0){
                return -1;
            }
    
            char ch = buf[pos++];
    
            count--;
    
            return ch;
        }
    
        // 定义从缓冲区读取一行字符的 readLine() 方法
        public String myReadLine() throws IOException{
    
            // 定义一个数组容器, 存储从缓冲区中获取到的数据
            StringBuilder sb = new StringBuilder();
    
            // 使用自定义的 MyRead 方法, 从缓冲区中不断获取单个字符,
            int ch = 0;
            while((ch=myRead()) != -1){
    
                if(ch=='
    ')
                    continue;
                if(ch=='
    ')
                    return sb.toString();
    
                // 将从缓冲区中读到的字符, 存储到缓存行数据的缓冲区中
                sb.append((char)ch);
            }
    
            // 如果最后一行结尾没有回车符, 缓冲区的读取已结束,
            // 但是并不能判断 if(ch=='
    '), 所有最后一行未能输出
            if(sb.length() != 0)
                return sb.toString();
    
            return null;
        }
    
        public void myClose() throws IOException{
            r.close();
        }
    
        }
    
    
    

    使用缓冲区的方式复制文本文件

    public class CopyTextByBufTest {
        public static void main(String[] args) throws IOException {
            FileReader fr = new FileReader("buf.txt");
            BufferedReader bufr = new BufferedReader(fr);
    
            FileWriter fw = new FileWriter("buf_copy.txt");
            BufferedWriter bufw = new BufferedWriter(fw);
    
            /*
             *  int ch = 0;
             *  // 使用缓冲区对象进行单个字符的读写
             *  // 这是直接从内存中读取单个字符, 不是从硬盘中
             *  while((ch=bufr.read()) != -1){
             *        bufw.write(ch);
             *    }
             */
    
             // 使用行进行读取文件
    
             String line = null;
             while((line=bufr.readLine())!=null){
                bufw.write(line);
                bufw.newLine();
                bufw.flush();  // 注意: 每次写入之后, 进行刷新保存
            }
    
            bufw.close();
            bufr.close();
    }
    }
    

    LineNumberReader 装饰类

    1. BufferedReader 的子类
    2. 可以跟踪行号的缓冲字符输入流
      • setLineNumber(int); : 设置当前行号
      • getLineNumber(); : 获取当前行号



    参考资料

  • 相关阅读:
    点击添加按钮添加一条记录,点击删除按钮删除本条记录
    两个input在一行让它们能对齐
    H5页面在微信中禁止下拉露出网页
    纯css实现隐藏滚动条仍可以滚动
    jQuery弹出层layer插件的使用
    flex组合流动布局实例---利用css的order属性改变盒子排列顺序
    媒体查询样式失效的解决办法
    menu-普通menu弹出框样式
    5lession-path路径相关操作
    do_pj--下拉代码脚本的使用
  • 原文地址:https://www.cnblogs.com/linkworld/p/7503698.html
Copyright © 2011-2022 走看看