BufferedReader源码分析
一个java小白
最近看BufferedReader的源码......难受的一批!!!这里分析一下
-
首先看下BufferedReader的构造方法
InputStream in = new FileInputStream("day08/note.txt"); BufferedReader bf = new BufferedReader(new InputStreamReader(in)); public InputStreamReader(InputStream in) { //初始化父类,Reader中有一个lock属性, protected Object lock; //记录当前实例。目的是保护该实例的操作 super(in); //sd的类型是StreamDecoder sd = StreamDecoder.forInputStreamReader(in, this, Charset.defaultCharset()); // ## check lock object } //看看forInputStreamReader准备干啥 public static StreamDecoder forInputStreamReader(InputStream in, Object lock, Charset cs) { return new StreamDecoder(in, lock, cs); } //继续跟踪 StreamDecoder(InputStream in, Object lock, Charset cs) { this(in, lock, cs.newDecoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE)); } //终于找到了 StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) { //不显示super()的话,会默认调用super(); super(lock); //字符集编码,编辑器的 this.cs = dec.charset(); //解码器 this.decoder = dec; // This path disabled until direct buffers are faster //不能执行 if (false && in instanceof FileInputStream) { ch = getChannel((FileInputStream)in); if (ch != null) bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE); } //ch 不明确其作用,大致知道是某个通道 if (ch == null) { this.in = in; this.ch = null; //创建HeapByteBuffer实例,大小为8192 bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE); } //flip()和clear()另外写随笔分析 bb.flip(); // So that bb is initially empty //limit=position //position=0 } //绕了一圈 public BufferedReader(Reader in) { this(in, defaultCharBufferSize); } // public BufferedReader(Reader in, int sz) { super(in); if (sz <= 0) throw new IllegalArgumentException("Buffer size <= 0"); //in等于InputStreamReader实例 this.in = in; //cb是一个char型数组 cb = new char[sz]; //nextChar是数组的下一个下标,nChars是数组中存了多个数据 nextChar = nChars = 0; }
初步总结下,以上完成了三件事
- 初始化Reader
- 创建StreamDecoder实例
- 创建BufferedReader实例,缓冲区为8192
StreamDecoder解码器分析
解码器的源码看的我眼花缭乱,跳来跳去。还是太菜了!!! :)
先解释下几个参数
- limit : 它指的是下一次读取或写入的位置。
- capaticy: 指定还有多少数据需要写出(在从缓冲区写入通道时),或者还有多少空间可以读入数据(在从通道读入缓冲区时),它初始化是与capacity的值一样,当调用flip()方法之后,它的值会改变成position的值,而position被置0。它箭头所指的位置是最后一位元素的下一位所在的位置。
- position: 指定了可以存储在缓冲区中的最大数据容量,实际上,它指定了底层数组的大小,或者至少是指定了准许我们使用的底层数组的容量,这个初始化后就不会再改变了。
后面遇到莫名的变量,可以看看是不是这三个
接下来就开始胡扯,首先给出例子
InputStream in = new FileInputStream("day08/note.txt");
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
int i;
while ((i =bf.read())!=-1){
System.out.println(i);
}
开始断点调试。
//BufferedReader中的read()
public int read() throws IOException {
//之前初始化Reader类的作用,执行同步代码块
synchronized (lock) {
//确认InputStreamReader流是开启的
ensureOpen();
//
for (;;) {
//第一次读取数据时,nextChar和nChars都是0,条件成立
//第二次条件成立,nextChar自增到等于nChars时,条件成立
if (nextChar >= nChars) {
//往private char cb[]中填充数据
fill();
//没有数据返回-1
if (nextChar >= nChars)
return -1;
}
//还没研究
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '
') {
nextChar++;
continue;
}
}
//放回cb数组中对应的数据,nextChar自增1
return cb[nextChar++];
}
}
}
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 {
//调用的是InputStreamReader实例对应的read()方法
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
//注意参数
public int read(char cbuf[], int offset, int length) throws IOException {
//调用的是StreamDecoder对应的read()
return sd.read(cbuf, offset, length);
}
//offset 等于0 length 等于8192
public int read(char cbuf[], int offset, int length) throws IOException {
int off = offset;
int len = length;
synchronized (lock) {
//再次检测流的情况
ensureOpen();
//不会执行
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0)
return 0;
//初始n值
int n = 0;
//还没研究
if (haveLeftoverChar) {
// Copy the leftover char into the buffer
cbuf[off] = leftoverChar;
off++; len--;
haveLeftoverChar = false;
n = 1;
if ((len == 0) || !implReady())
// Return now if this is all we can produce w/o blocking
return n;
}
//一个一个读,执行
if (len == 1) {
// Treat single-character array reads just like read()
int c = read0();
if (c == -1)
return (n == 0) ? -1 : n;
cbuf[off] = (char)c;
return n + 1;
}
//继续看implRead方法
return n + implRead(cbuf, off, off + len);
}
}
//
int implRead(char[] cbuf, int off, int end) throws IOException {
// In order to handle surrogate pairs, this method requires that
// the invoker attempt to read at least two characters. Saving the
// extra character, if any, at a higher level is easier than trying
// to deal with it here.
//断言
assert (end - off > 1);
//创建一个字符缓冲流
//改变cb就会改变出传入实参cbuf,也就会改变BufferReader实例中数组cb
CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
if (cb.position() != 0)
// Ensure that cb[0] == cbuf[off]
cb = cb.slice();
//结束标志
boolean eof = false;
for (;;) {
//解码的真正位置所在,后面在写,太长了!!!具体是通过ASCII码值转化
//数组bb(StreamDecoder内置属性)数据解码到数组cb中
CoderResult cr = decoder.decode(bb, cb, eof);
//下溢代表输入流为空,需要补充数据到输入缓冲区
if (cr.isUnderflow()) {
if (eof)
break;
//判断数组中是否还有空位置存数据
if (!cb.hasRemaining())
break;
if ((cb.position() > 0) && !inReady())
break; // Block at most once
//调用
int n = readBytes();
//调用
/*
private int readBytes() throws IOException {
//compact()调用了System.arraycopy(hb, ix(pos), hb, ix(0), rem);
//保证偏移量是从0开始
//前面调用flip()不知道是否还记得。limit=position=0
//int rem = limit() - pos;结果是0
public ByteBuffer compact() {
int pos = position();0
int rem = limit() - pos;0
System.arraycopy(hb, ix(pos), hb, ix(0), rem);
position(rem);0
limit(capacity());8192
discardMark();
return this;
}
bb.compact();
try {
if (ch != null) {
// Read from the channel
int n = ch.read(bb);
if (n < 0)
return n;
} else {
// Read from the input stream, and then update the buffer
int lim = bb.limit();8192
int pos = bb.position();0
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
assert rem > 0;
//调用FileInputStream中read方法
int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
if (n < 0)
return n;
if (n == 0)
throw new IOException("Underlying input stream returned zero bytes");
assert (n <= rem) : "n = " + n + ", rem = " + rem;
//重新更新position
bb.position(pos + n);
}
} finally {
// Flip even when an IOException is thrown,
// otherwise the stream will stutter
//读取的前提
bb.flip();
}
int rem = bb.remaining();
assert (rem != 0) : rem;
return rem;
}
*/
if (n < 0) {
eof = true;
if ((cb.position() == 0) && (!bb.hasRemaining()))
break;
decoder.reset();
}
continue;
}
if (cr.isOverflow()) {
assert cb.position() > 0;
break;
}
cr.throwException();
}
if (eof) {
// ## Need to flush decoder
decoder.reset();
}
if (cb.position() == 0) {
if (eof)
return -1;
assert false;
}
return cb.position();
}
总结解码器在BufferReader和InputStream中起到一个转化作用,通过将输入源转化成字节流,在通过ASCII码一个一个的赋值给字符流。