今天来学习一下 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的更多相关文章

  1. javaIO——BufferedReader效率测试实践

    上一篇刚刚学习了 BufferedReader ,想着来验证一下 BufferedReader 的缓冲到底能带来多大的性能提升,于是拷贝了一个100M 左右的日志文件放到本地,测试一下使用 Buffe ...

  2. java基础知识回顾之javaIO类---BufferedReader和BufferedWriter

    使用了装饰设计模式:此类的设计是为了提高流操作数据的效率.思想就是定义容器将数据进行临时存储,对于缓冲区对象,其实就是将这个容器进行了分装,并提供了更高效的操作方法. BufferReader: pa ...

  3. Java基础---Java---IO流-----BufferedReader、BufferedWriter、缓冲区、装饰设计模式及和继承的区别

    IO流 IO流用来处理设备之间的数据传输 java对数据的操作是过流的方式 流按操作数据分为两种:字节流与字符流 流按流向分为:输入流,输出流. IO流常用基类 字节流的抽象基类:InputStrea ...

  4. Java-IO之BufferedReader(字符缓冲输入流)

    BufferedReader是缓冲字符输入流,继承于Reader,BufferedReader的作用是为其他字符输入流添加一些缓冲功能. BufferedReader主要的函数列表: Buffered ...

  5. Java-IO流之BufferedReader 和BufferedWriter的使用和原理

    BufferedReader和BufferedWriter出现的目的是为了对FileReader以及FileWriter的读写操作进行增强,而怎么增强呢,原理类似于使用StringBuilder,是把 ...

  6. [二十一]JavaIO之BufferedReader 与 BufferedWriter

    功能简介 BufferedReader  从字符输入流中读取文本,内部缓冲各个字符,从而实现字符.数组和行的高效读取 BufferedWriter 将文本写入字符输出流,内部缓冲各个字符,从而提供单个 ...

  7. java-IO流-字符流-FileReader、FileWriter、自定义小数组的拷贝、BufferedReader、BufferedWriter、readLine()和newLine()方法、LineNumberReader、使用指定的码表读写字符

    ###21.01_IO流(字符流FileReader) * 1.字符流是什么     * 字符流是可以直接读写字符的IO流     * 字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要 ...

  8. javaIO系统----再看装饰者模式

    javaIO系统拥有各种各样的类,尤其是每次要进行读写操作时,总会一层套一层的new,以前不明白为什么要这样做,不过学习了适配器模式后,对于这种做法立刻了解了:动态扩展IO的功能,使之符合使用者的习惯 ...

  9. Java学习日记之 Java-IO流

    Java中的IO流在处理上分为字节流和字符流.字节流和字符流的区别 : 1.字节流读取的时候,读到一个字节就返回一个字节:  字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8 ...

随机推荐

  1. win10windows无法创建快捷方式 请检查磁盘

      这个是因为文件没有权限造成的   打开"我的电脑",菜单栏里选择"工具"-"文件夹选项"-"查看",把里面" ...

  2. SQL-W3School-高级:SQL LEFT JOIN 关键字

    ylbtech-SQL-W3School-高级:SQL LEFT JOIN 关键字 1.返回顶部 1. SQL LEFT JOIN 关键字 LEFT JOIN 关键字会从左表 (table_name1 ...

  3. Web Service 实例基于Socket创建Web服务

    ServerSocket服务器端代码如下: public static void main(String[] args) throws IOException { // 1:建立服务器端的tcp so ...

  4. smarty建的mvc环境

    ================================搭建MVC结构================================基于MVC,解耦合 (高内聚,低耦合),优点:易维护.易扩 ...

  5. 新西兰程序员 ASP.NET网站中设置404自定义错误页面

    新西兰程序员 ASP.NET网站中设置404自定义错误页面 在用ASP.NET WebForm开发一个网站时,需要自定义404错误页面. 做法是这样的 在网站根目录下建立了一个404.html的错误页 ...

  6. ckpt convert to pb

    import tensorflow as tf #from create_tf_record import * from tensorflow.python.framework import grap ...

  7. 阶段5 3.微服务项目【学成在线】_day04 页面静态化_08-freemarker基础-空值处理

    把stus注释掉 正常访问就会报错 第20行 这里的stus为空,所以造成了这个错误. 非空判断 不为空用双问号来判断 <#if stus??><#list stus as stu& ...

  8. @vue/cli3中解决Elint中console.log报错的问题

    方法一:package.json中”eslintConfig”>"rules”字段添加如下代码 "no-console": "off", &qu ...

  9. 安卓运行linux应用程序

    安卓是可以运行linux应用程序的,安卓系统原来就基于Linux.但是安卓已经把linux改头换面了.具体方法是安装Termux软件,然后就可以运行pkg命令安装软件包了,希望可以帮助到大家.

  10. Hbase 学习记录

    说明: 公司最近要使用HBase 用于(冷)历史数据 存储,和简单离线计算.在一次讨论会上,我发表意见,为什么把近期数据流程热点数据库中,并且继续异步流入到 历史数据库HBase 里面.提供高效查询等 ...