javaIO——BufferedReader
今天来学习一下 java.io.BufferedReader ,从命名可以看出,跟前面学习的 StringReader 和 CharArrayReader 有些不一样,这些都是按照数据源类型命名,BufferedReader 显然不是。BufferedReader 字面意思即是“缓冲读取器”,所以它肯定是对其它读取器进行一个包装,然后提供缓冲的功能。看一下注释:Reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines. 从一个字符输入流读取文本,通过缓冲字符从而提供对字符、数组和行的高效读取。
1. 关键字段

上图红框中为 BufferedReader 的关键字段:
1.1. in 是它包装的真正提供数据输入的读取器;
1.2. cb[] 是缓冲区,可以在构造方法中指定缓冲区大小,不指定即使用默认值 private static int defaultCharBufferSize = 8192; ;
1.3. nChars 是缓冲区当前的有效的长度(假如 cb.length = 1024,nChars=128,就表示当前缓冲了 128 个字符,128~1023 的索引位置没有意义);
1.4. nextChar 表示缓冲区中尚未被读取的字符的开始位置(如上例, 假如 nextChar=90,表示缓冲区当前有 128 个字符,但是 0~89 索引位的字符已经被读取过了,也就是失效了);
2. 核心方法
2.1. fill() ,填充缓冲区:
/**
* Fills the input buffer, taking the mark into account if it is valid.
*/
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;
}
}
fill()
上述方法中,前面一部分都是计算本次填充应该从缓冲区的什么位置开始(牵涉到流的标记什么的,这个暂时没有深究)。关键部分是这几行:

2.2. read() 和 read(char cbuf[], int off, int len) ,提供给外部调用的读取方法:
前面说了,BufferedReader 只是一个包装类,所以它应该将被包装对象的功能提供,所以 read 方法必不可少。
read() ,读取单个字符的方法:

read(char cbuf[], int off, int len) ,读取多个字符的方法:

可以看到,这个方法并没有调用 fill(),而是调用 read1 方法,那我们再来看看 read1 方法:

可以看出,只有当缓冲区为空了,才会尝试去填充缓冲区,这也就解答了前面提问“为什么可以直接将有效位置置为本次填充开始位置”
3. 总结:
3.1. 只有当缓冲区为空时,才会调用 fill() 方法,从真正的数据流中读取数据填充到缓冲区;
3.2. 每次填充缓冲区,都尝试将缓冲区填满(但不保证填满,这取决于 被包装流的 read 实现);
3.3. 填充缓冲区时,会阻塞直至读取到有效数据至缓冲区(想想如果不阻塞,也没有意义,因为根据 3.1,没有读到有效数据返回也是徒然);
3.4. 对于多字符读取方法,会阻塞直至读取到参数指定长度的内容,或者流结束;
【附】实践篇:
BufferedReader 效率测试实践:https://www.cnblogs.com/coding-one/p/11369976.html
javaIO——BufferedReader的更多相关文章
- javaIO——BufferedReader效率测试实践
上一篇刚刚学习了 BufferedReader ,想着来验证一下 BufferedReader 的缓冲到底能带来多大的性能提升,于是拷贝了一个100M 左右的日志文件放到本地,测试一下使用 Buffe ...
- java基础知识回顾之javaIO类---BufferedReader和BufferedWriter
使用了装饰设计模式:此类的设计是为了提高流操作数据的效率.思想就是定义容器将数据进行临时存储,对于缓冲区对象,其实就是将这个容器进行了分装,并提供了更高效的操作方法. BufferReader: pa ...
- Java基础---Java---IO流-----BufferedReader、BufferedWriter、缓冲区、装饰设计模式及和继承的区别
IO流 IO流用来处理设备之间的数据传输 java对数据的操作是过流的方式 流按操作数据分为两种:字节流与字符流 流按流向分为:输入流,输出流. IO流常用基类 字节流的抽象基类:InputStrea ...
- Java-IO之BufferedReader(字符缓冲输入流)
BufferedReader是缓冲字符输入流,继承于Reader,BufferedReader的作用是为其他字符输入流添加一些缓冲功能. BufferedReader主要的函数列表: Buffered ...
- Java-IO流之BufferedReader 和BufferedWriter的使用和原理
BufferedReader和BufferedWriter出现的目的是为了对FileReader以及FileWriter的读写操作进行增强,而怎么增强呢,原理类似于使用StringBuilder,是把 ...
- [二十一]JavaIO之BufferedReader 与 BufferedWriter
功能简介 BufferedReader 从字符输入流中读取文本,内部缓冲各个字符,从而实现字符.数组和行的高效读取 BufferedWriter 将文本写入字符输出流,内部缓冲各个字符,从而提供单个 ...
- java-IO流-字符流-FileReader、FileWriter、自定义小数组的拷贝、BufferedReader、BufferedWriter、readLine()和newLine()方法、LineNumberReader、使用指定的码表读写字符
###21.01_IO流(字符流FileReader) * 1.字符流是什么 * 字符流是可以直接读写字符的IO流 * 字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要 ...
- javaIO系统----再看装饰者模式
javaIO系统拥有各种各样的类,尤其是每次要进行读写操作时,总会一层套一层的new,以前不明白为什么要这样做,不过学习了适配器模式后,对于这种做法立刻了解了:动态扩展IO的功能,使之符合使用者的习惯 ...
- Java学习日记之 Java-IO流
Java中的IO流在处理上分为字节流和字符流.字节流和字符流的区别 : 1.字节流读取的时候,读到一个字节就返回一个字节: 字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8 ...
随机推荐
- 通过generate解析SQL日志生成xml进行SQL回放
查看Oracle redo日志来分析SQL执行记录 1)设置Oracle数据字典导出路径参数(可选) shutdown immediatealter system set UTL_FILE_DIR=' ...
- SQL-W3School-高级:SQL IN 操作符
ylbtech-SQL-W3School-高级:SQL IN 操作符 1.返回顶部 1. IN 操作符 IN 操作符允许我们在 WHERE 子句中规定多个值. SQL IN 语法 SELECT col ...
- 周志华-机器学习西瓜书-第三章习题3.5 LDA
本文为周志华机器学习西瓜书第三章课后习题3.5答案,编程实现线性判别分析LDA,数据集为书本第89页的数据 首先介绍LDA算法流程: LDA的一个手工计算数学实例: 课后习题的代码: # coding ...
- set serveroutput on
使用set serveroutput on 命令设置环境变量serveroutput为打开状态,从而使得pl/sql程序能够在SQL*plus中输出结果 使用函数dbms_output.put_lin ...
- osg help
#ifdef _WIN32#include <Windows.h>#endif // _WIN32 #include <osgViewer/Viewer>#include &l ...
- Windows10 64位 安装 Docker
本文主要介绍Docker在Windows下的安装.关于Docker的介绍和文档在其官网中可以找到:http://www.docker.com .安装环境:Windows10 64位. Docker引擎 ...
- 开发CLI命令行
命令行工具:CLI 是在命令行终端使用的工具,如git, npm, vim 都是CLI工具.比如我们可以通过 git clone 等命令简单把远程代码复制到本地 和 cli 相对的是图形用户界面(gu ...
- python进阶----logging模块
在工作中经常要打印一些日志,下面介绍一下python中的logging模块 首先,先了解一下日志的级别,主要分为以下5种: debug 最低级别,一般开发用来打印一些调试信息 info ...
- Java学习笔记-设计模式
常见设计模式有23种,设计模式是解决某一类问题最行之有效的方法 单例设计模式 解决一个类在内存中只存在一个对象 思想 为了避免其他程序过多建立该类对象.先禁止其他程序建立该类对象 还为了让其他程序可以 ...
- kindeditor 在JSP 中上传文件的配置
1.将kindeditor,jsp,lib目录下的jar文件放到工程的lib目录下 2.将admin-login.jsp,upload_json.jsp,复制到admin的files目录下 3.复制以 ...