java源码-BufferedReader
开篇
在设计模式中有一种叫做装饰者模式,刚好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作为基类。
装饰设计模式
装饰设计模式:javaIO技术中的装饰设计模式,对一组对象的功能进行增强时,就可以使用该设计模式

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Mac的神功能:快速预览功能你真的会用吗?
关注九天学者微信公众号(扫码关注)第一时间获取技术贴更新! 问:什么是快速预览功能? 答:快速预览就是苹果Mac系统下原生的一个快速查看文件内容的功能,英文叫Quick Look或者Quick Preview。不需要双击打开文件,只需要选中文件再按空格键就能看到内容,再按一次空格键预览窗口就消失。速度非常快,我敢说没人不喜欢这个功能。好像新版的win10系统也有这个功能了。 原生快速预览的限制 文本文件后缀名 Mac原生的快速预览功能能支持的文件类型不是很广。比如同样是文本文件,如果后缀名是.txt可以预览,但是你把后缀名改为.dat则无法预览。 原生预览支持txt后缀名的文本文件 文件名修改为dat之后不可预览 QLStephen插件 这个插件可以支持所有后缀名的文本文件的预览,甚至是没有后缀名的比如我们常用的README文件(内容一般都是Markdown写的)。安装很简单:终端运行 brew cask install qlstephen即可。现在看看下面的效果截图(注:如果你没有brew,那说明你还是个不太会用Mac的用户,应该是个只注重计算机颜值而不注重灵魂的用户 ) QLste...
- 下一篇
关于C++、PHP和Swoole
昨天和一个前同事聊天,各种吐槽PHP,吐槽Swoole,他认为PHP到处是坑,PHP局限很大。PHP+Swoole不适合做高并发服务器,C+Swoole才是最好的方案。C++有各种数据结构,C++可以开线程,C++可以共享对象。看来有必要好好得说明一下了。 PHP比C/C++或Java少了什么?多线程,多线程,多线程…… 是的。PHP比C/C++、Java少了多了多线程。PHP只有多进程的方案,所以PHP里的全局变量和对象不是共享的、数据结构也不能跨进程操作、Socket文件描述符不能共享等等。所以PHP有局限? 多线程看似比多进程要强大很多,实际上我可以负责任的告诉你,多线程带来的坑更多。 数据同步问题会让你崩溃的。要么就牺牲性能到处加锁,要么就用地狱难度的无锁并发编程,据我所知目前国内能掌握此项技能的人凤毛麟角。 不要以为加锁就万事大吉了,你会在死锁问题上栽个大跟头。当你的程序逻辑复杂后,锁越来越难控制了,一旦死锁你的程序基本上就完了。 某个线程挂了那所有线程都会退出 反而在看多进程,其实就简单的多了。 配合进程间通信,基本上你可以实现任意的数据共享。比如利用一个进程专门存数据结构...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Mario游戏-低调大师作品
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS关闭SELinux安全模块