您现在的位置是:首页 > 文章详情

java源码-BufferedReader

日期:2018-09-11点击:399

开篇

在设计模式中有一种叫做装饰者模式,刚好BufferedReader的源码是这个设计模式的最好例子,一并看下源码。


源码分析

构造函数

  • BufferedReader的类变量的Reader in 用以构造函数参数中的Reader in参数,BufferedReader的所有读写操作都通过Reader对象进行操作。
  • BufferedReader相当于针对内部的Reader对象进行了一层包装,可以理解为装饰者。
public class BufferedReader extends Reader { private Reader in; private char cb[]; //nextChar代表下次要读取的位置,nChars表示总共的字符个数 private int nChars, nextChar; private static final int INVALIDATED = -2; private static final int UNMARKED = -1; private int markedChar = UNMARKED; private int readAheadLimit = 0; /* Valid only when markedChar > 0 */ private boolean skipLF = false; private boolean markedSkipLF = false; private static int defaultCharBufferSize = 8192; private static int defaultExpectedLineLength = 80; 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 in对象读取字符到指定数量的字符数据到cb数组当中。
  • dst表示保存数据的起始位置,cb.length-dst表示读取字符的个数。
  • 在执行read和readline操作的之前如果cb当中可读字符不足会先执行fill()读取字符。
 private void fill() throws IOException { int dst; if (markedChar <= UNMARKED) { /* No mark */ dst = 0; } else { // 省略一部分代码 } int n; do { // 从底层input读取数据到cb,cb中起始位置是dst, // 读取的长度是cb的lenght减去起始位置dst,理解剩余能够装的字符 n = in.read(cb, dst, cb.length - dst); } while (n == 0); if (n > 0) { // 设置最大可读字符结束位置 nChars = dst + n; // 设置可读字符的起始位置 nextChar = dst; } } 



read过程

  • 读取过程中如果满足条件(nextChar 表示下一个读取字符>= nChars可用字符),代表字符已经读取完毕那么就通过fill()进行预加载。
  • 读取当前字符并累加当前可读取字符,执行nextChar++操作。
 public int read() throws IOException { synchronized (lock) { ensureOpen(); for (;;) { if (nextChar >= nChars) { fill(); if (nextChar >= nChars) return -1; } if (skipLF) { skipLF = false; if (cb[nextChar] == '\n') { nextChar++; continue; } } // 读取当前字符并累加下一个读取位置 return cb[nextChar++]; } } } 



readline过程

  • 读取过程中如果满足条件(nextChar 表示下一个读取字符>= nChars可用字符),代表字符已经读取完毕那么就通过fill()进行预加载。
  • 读取过程中如果遇到\r\n则中断循环,通过str = new String(cb, startChar, i - startChar)返回整行数据。
 String readLine(boolean ignoreLF) throws IOException { //读取的数据最终放在这个s中, StringBuffer s = null; int startChar; synchronized (lock) { ensureOpen(); boolean omitLF = ignoreLF || skipLF; bufferLoop: for (;;) { if (nextChar >= nChars) fill(); if (nextChar >= nChars) { /* EOF */ if (s != null && s.length() > 0) //从这里返回,可能是因为读取的数据最后没有以\n或\r结束 return s.toString(); else // 从这里返回,是因为开始读的时候,就已经是input的末尾了, // 所以s本身就没有被初始化,只能返回null return null; } boolean eol = false; char c = 0; int i; /* Skip a leftover '\n', if necessary */ if (omitLF && (cb[nextChar] == '\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; } } startChar = nextChar; nextChar = i; if (eol) { String str; // 运行到这,s为null,说明是第一次循环中就读到了行尾。 if (s == null) { str = new String(cb, startChar, i - startChar); } else { // 运行到这,起码说明是第二次循环了,s里已经有了第一次读取的数据 s.append(cb, startChar, i - startChar); str = s.toString(); } nextChar++; if (c == '\r') { skipLF = true; } // 运行到这说明读到了行尾,返回str return str; } if (s == null) s = new StringBuffer(defaultExpectedLineLength); // 运行到这说明,读取了整个cb的数据,发现一直没有\n或者\r, // 之后回到最初循环继续读取。 s.append(cb, startChar, i - startChar); } } } 


类依赖图

  • BufferedReader的类依赖图如下图,所有的io reader都是继承自Reader作为基类。


    img_62acfe3000fc52dee4f6ff8ac42c2045.png


装饰设计模式

装饰设计模式:javaIO技术中的装饰设计模式,对一组对象的功能进行增强时,就可以使用该设计模式

原文链接:https://yq.aliyun.com/articles/666289
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章