BufferReader

BufferReader

1.1 测试样例

先看这样一段测试代码 ,代码的基本功能就是读文本,然后输出到控制台。以下的说明都是根据这段测试代码展开

 public static void main(String[] args) {
        try {
            BufferedReader bufferedReader = new BufferedReader(new                                 
            FileReader("D:\\WORKSPACE\\template.txt"));
            String str;
            StringBuffer stringBuffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                stringBuffer.append(str + System.getProperty("line.separator"));
            }
            System.out.println(stringBuffer.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

1.2 设计模式

BufferedReader采用了装饰者模式,装饰者模式目的在于扩展被修饰者功能,通过上例的BufferReader的构造方法, BufferedReader bufferedReader = new BufferedReader(new FileReader(“D:\WORKSPACE\template.txt”)); 可以看出BufferReader是用来装饰FileReader的,增强FileReader的功能。详细见下图比较
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

1.3 源码解析

1.3.1 API文档翻译


   使用输入流读文本时,缓存字符以便高效的读取字符,数组和文本行
缓存大小可以是自定义,也可以使用默认的,默认的大小是足够应付大多数情况了
   一般情况下,都是Reader包装字节流,因此我们建议使用BufferedReader去包装字符流他的方法Read()是更有价值IDE,比如        FileReader和InputStreamReader. 比如
eg.BufferedReader in
= new BufferedReader(new FileReader("foo.in"));
将缓存输入从指定的文件,没有缓存的话,每一次读Read方法和readline方法可能会造成先把文件读成字节,然后在转字符,然后返回,    这样效率将是非常低的。
   使用DataInputStreams进行文本输入的程序可以通过用适当的BufferedReader替换每个DataInputStream来进行本地化。

1.3.2 代码执行流程

当执行 BufferedReader bufferedReader = new BufferedReader(new FileReader(“D:\WORKSPACE\template.txt”))时

  • 给父类的lock值赋值为FileReader,用于之后的代码同步
  • 给全局变量Reader in 赋值为FileReader
  • 初始化缓存的全局字符数组cb,默认长度是8192,可缓存的数据大小是8192*2/1024=16kb
  • 给全局变量指针nextchar赋值为0,nextchar意思是读到缓存字符数组cb到哪个位置了(读了多少个字节了),不是读到文件内文本数据到哪了。nchar是cb中具体字节大小。这部分下面会通过代码具体介绍。
BufferedReader.class

    public BufferedReader(Reader in, int sz) {
        super(in);
        if (sz <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
        this.in = in;
        cb = new char[sz];
        nextChar = nChars = 0;
    }
    public BufferedReader(Reader in) {
        this(in, defaultCharBufferSize);
    }
-----------------------------------------------------------------------------------------------------------
Reader.class 
    
    protected Reader(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }    

当执行bufferedReader.readLine()时

  • 输入流将文本读入缓存变量cb[]中。默认读16Kb文本大小到此数组中,上面有介绍。
  • 读缓存变量中的数据,读到了\r,\n或者\r\n,程序知道了这是一行的结尾了,此时程序就将之前读到的字符返回,readline方法执行完毕
  • 如果读到末尾发现程序中没有\r,\n或者\r\n,那么我们知道此时读的文本肯定大于16kb,还有没有读完,此时调用fill方法读剩余的文本。然后重复上一步。下面是代码的详细注释。
  public String readLine() throws IOException {
        return readLine(false);
  }
  String readLine(boolean ignoreLF) throws IOException {
        StringBuffer s = null;  //主要作用是readline方法的值返回,注意的一点是如果读到缓存流最后没有读到换行符,则会执行                                //s.append(cb, startChar, i - startChar);然后再去调用fill来重新填充缓存字符数组来读                                //并直到读到换行符,来追加字符。
        int startChar;         //nextChar会赋值个startChar用于分割cb
        synchronized (lock) {  //加锁防止读入脏数据
            ensureOpen();      //确保Reader in不是空的
            boolean omitLF = ignoreLF || skipLF;   //omitLF的值由skipLF的值的控制,ignoreLF在这里都是false,这个值                                                    //主要用来处理换行符是\r\n的情况
        bufferLoop:                               //循环的标签,并没啥用
            for (;;) {                            //死循环,在循环中用return来打断死循环   
                         
                if (nextChar >= nChars)          //nchars表示cb缓存数组实际缓存文本的字节数大小。nextChar标识此时指向                                               //cb哪个字节数,如果nextChar = nChars = 0 标识此时还没有读文本,                                               //如果nextChar和nChars不等于0,且满足nextChar >= nChar表示缓存读完。需重                                              //新填充缓存
                    fill();             //填充缓存
                if (nextChar >= nChars) { /* EOF */       
                    if (s != null && s.length() > 0)
                        return s.toString();        
                    else
                        return null;
                }                                 //判断文件是否读完了。
                boolean eol = false;              //一行是否读完的标志
                char c = 0;                        
                int i;

                /* Skip a leftover '\n', if necessary */
                if (omitLF && (cb[nextChar] == '\n'))  // 判断结尾/r/n的情况
                    nextChar++;
                skipLF = false;                         
                omitLF = false;

            charLoop:
                for (i = nextChar; i < nChars; i++) {
                    c = cb[i];
                    if ((c == '\n') || (c == '\r')) {
                        eol = true;
                        break charLoop;
                    }
                }                              //判断是否有读到换行符,如果读到标识一行结束,设置eof为true

                startChar = nextChar;           
                nextChar = i;

                if (eol) {
                    String str;
                    if (s == null) {
                        str = new String(cb, startChar, i - startChar);
                    } else {
                        s.append(cb, startChar, i - startChar);
                        str = s.toString();
                    }
                    nextChar++;
                    if (c == '\r') {
                        skipLF = true;
                    }
                    return str;
                }                 //如果读到了文件末尾,则直接截取cb作为字符串返回。

                if (s == null)
                    s = new StringBuffer(defaultExpectedLineLength);
                s.append(cb, startChar, i - startChar);
            }
        }
    }
      private void fill() throws IOException {
        int dst;
        if (markedChar <= UNMARKED) {
            /* No mark */
            dst = 0;
        } else {
            /* Marked */
            int delta = nextChar - markedChar;
            if (delta >= readAheadLimit) {
                /* Gone past read-ahead limit: Invalidate mark */
                markedChar = INVALIDATED;
                readAheadLimit = 0;
                dst = 0;
            } else {
                if (readAheadLimit <= cb.length) {
                    /* Shuffle in the current buffer */
                    System.arraycopy(cb, markedChar, cb, 0, delta);
                    markedChar = 0;
                    dst = delta;
                } else {
                    /* Reallocate buffer to accommodate read-ahead limit */
                    char ncb[] = new char[readAheadLimit];
                    System.arraycopy(cb, markedChar, ncb, 0, delta);
                    cb = ncb;
                    markedChar = 0;
                    dst = delta;
                }
                nextChar = nChars = delta;
            }
        }

        int n;
        do {
            n = in.read(cb, dst, cb.length - dst);
        } while (n == 0);
        if (n > 0) {
            nChars = dst + n;
            nextChar = dst;
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值