java的bufferedreader_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. 关键字段

4f9103fcbaf2581ac5f1bbb0ddb04a0f.png

上图红框中为 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() ,填充缓冲区:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

/*** Fills the input buffer, taking the mark into account if it is valid.*/

private void fill() throwsIOException {intdst;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;

}

}intn;do{

n= in.read(cb, dst, cb.length -dst);

}while (n == 0);if (n > 0) {

nChars= dst +n;

nextChar=dst;

}

}

fill()

上述方法中,前面一部分都是计算本次填充应该从缓冲区的什么位置开始(牵涉到流的标记什么的,这个暂时没有深究)。关键部分是这几行:

2336fee4aeddcc90818d966f336c8d63.png

2.2. read() 和 read(char cbuf[], int off, int len) ,提供给外部调用的读取方法:

前面说了,BufferedReader 只是一个包装类,所以它应该将被包装对象的功能提供,所以 read 方法必不可少。

read() ,读取单个字符的方法:

42911b95067c0e8a5994a39d468e6993.png

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

e447c0658f14014253e888f2bb70fd4c.png

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

84331100ba65b41f0bd039b99ee4ec50.png

可以看出,只有当缓冲区为空了,才会尝试去填充缓冲区,这也就解答了前面提问“为什么可以直接将有效位置置为本次填充开始位置”

3. 总结:

3.1. 只有当缓冲区为空时,才会调用 fill() 方法,从真正的数据流中读取数据填充到缓冲区;

3.2. 每次填充缓冲区,都尝试将缓冲区填满(但不保证填满,这取决于 被包装流的 read 实现);

3.3. 填充缓冲区时,会阻塞直至读取到有效数据至缓冲区(想想如果不阻塞,也没有意义,因为根据 3.1,没有读到有效数据返回也是徒然);

3.4. 对于多字符读取方法,会阻塞直至读取到参数指定长度的内容,或者流结束;

【附】实践篇:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值