Java BufferedReader相关源码实例分析

时间:2021-05-20

1、案例代码

假设b.txt存储了abcdegfhijk

public static void main(String[] args) throws IOException { //字符缓冲流 BufferedReader bufferedReader=new BufferedReader(new FileReader (new File("H:\\ioText\\b.txt")),8); //存储读取的数据 char[] charsRead=new char[5]; //读取数据 bufferedReader.read(charsRead); //遍历并输出charsRead for (char c:charsRead){ System.out.println(c); } }

2、通过源码(部分)分析案例

a、第一次读取

public class BufferedReader extends Reader { private Reader in;//字符流 private char cb[];//缓冲区 private int nChars, nextChar;//nChars缓冲区可读字符数,nextChar下一个字符位置 private static final int INVALIDATED = -2; private static final int UNMARKED = -1; private int markedChar = UNMARKED; private int readAheadLimit = 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; //给缓冲区指定空间大小(案例指定为8) cb = new char[sz]; //缓冲区可读字符数和下一个字符位置初始化为0 nextChar = nChars = 0; } //读取数据 public int read(char cbuf[], int off, int len) throws IOException { synchronized (lock) { ensureOpen(); if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } //调用read1方法进行读取(真正读取数据的方法是read1方法) int n = read1(cbuf, off, len); if (n <= 0) return n; //将之前没处理完的数据复制到自定以数组charsRead再次调用read1方法读取 while ((n < len) && in.ready()) { int n1 = read1(cbuf, off + n, len - n); if (n1 <= 0) break; n += n1; } return n; } } //cbuf用户自定义数组(charsRead),off=0,len=5 private int read1(char[] cbuf, int off, int len) throws IOException { if (nextChar >= nChars) {//第一次读nextChar、nChars都为0,满足条件 if (len >= cb.length && markedChar <= UNMARKED && !skipLF) { return in.read(cbuf, off, len); } //刷新缓冲区,先往下找到fill方法源码分析 fill(); } if (nextChar >= nChars) return -1; if (skipLF) { skipLF = false; if (cb[nextChar] == '\n') { nextChar++; if (nextChar >= nChars) fill(); if (nextChar >= nChars) return -1; } } //执行完fill方法到这里,(len=5,nChars - nextChar=8-0)->n=5 int n = Math.min(len, nChars - nextChar); //将缓冲区cb从nextChar开始复制n=5个字符到自定义数组 System.arraycopy(cb, nextChar, cbuf, off, n); //nextChar=5 nextChar += n; //n=5 return n; } //刷新缓冲区方法 private void fill() throws IOException { int dst; if (markedChar <= UNMARKED) {//markedChar初始值为UNMARKED,满足条件 dst = 0;//初始化dst } else { int delta = nextChar - markedChar; if (delta >= readAheadLimit) { markedChar = INVALIDATED; readAheadLimit = 0; dst = 0; } else { if (readAheadLimit <= cb.length) { System.arraycopy(cb, markedChar, cb, 0, delta); markedChar = 0; dst = delta; } else { char ncb[] = new char[readAheadLimit]; System.arraycopy(cb, markedChar, ncb, 0, delta); cb = ncb; markedChar = 0; dst = delta; } nextChar = nChars = delta; } }​ int n; do { //dst=0,cb.length - dst=8-0->n=8 n = in.read(cb, dst, cb.length - dst); } while (n == 0); if (n > 0) {//满足条件 //nChars=8 nChars = dst + n; //nextChar=0 nextChar = dst; } } }

第一次读取后charsRead存储了五个字符:abcde

b、第二次读取

//cbuf用户自定义数组(charsRead),off=0,len=5 private int read1(char[] cbuf, int off, int len) throws IOException { if (nextChar >= nChars) {//第二次读nextChar=5、nChars=8,不满足条件 if (len >= cb.length && markedChar <= UNMARKED && !skipLF) { return in.read(cbuf, off, len); } fill(); } if (nextChar >= nChars) return -1; if (skipLF) { skipLF = false; if (cb[nextChar] == '\n') { nextChar++; if (nextChar >= nChars) fill(); if (nextChar >= nChars) return -1; } } //跳过if直接到这里,len=5,nChars - nextChar=8-5=3->n=3 int n = Math.min(len, nChars - nextChar); //将缓冲区cb从nextChar=5开始复制n=3个字符到自定义数组 System.arraycopy(cb, nextChar, cbuf, off, n); //nextChar=5+3=8 nextChar += n; //n=8 return n; }

第二次读取只读了三个字符把charsRead五个字符的前三个覆盖:fghde

c、第三次读取

//cbuf用户自定义数组(charsRead),off=0,len=5 private int read1(char[] cbuf, int off, int len) throws IOException { if (nextChar >= nChars) {//第三次读nextChar=8、nChars=8,满足条件 if (len >= cb.length && markedChar <= UNMARKED && !skipLF) { return in.read(cbuf, off, len); } //刷新缓冲区,先往下找到fill方法源码分析 fill(); } if (nextChar >= nChars) return -1; if (skipLF) { skipLF = false; if (cb[nextChar] == '\n') { nextChar++; if (nextChar >= nChars) fill(); if (nextChar >= nChars) return -1; } } //执行完fill方法到这里,(len=2,nChars - nextChar=8-0)->n=2 int n = Math.min(len, nChars - nextChar); //将缓冲区cb从nextChar=0开始复制n=2个字符到自定义数组 System.arraycopy(cb, nextChar, cbuf, off, n); //nextChar=5+3=8 nextChar += n; //n=8 return n; } //刷新缓冲区方法 private void fill() throws IOException { int dst; if (markedChar <= UNMARKED) {//markedChar初始值为UNMARKED,满足条件 dst = 0;//初始化dst } else { int delta = nextChar - markedChar; if (delta >= readAheadLimit) { markedChar = INVALIDATED; readAheadLimit = 0; dst = 0; } else { if (readAheadLimit <= cb.length) { System.arraycopy(cb, markedChar, cb, 0, delta); markedChar = 0; dst = delta; } else { char ncb[] = new char[readAheadLimit]; System.arraycopy(cb, markedChar, ncb, 0, delta); cb = ncb; markedChar = 0; dst = delta; } nextChar = nChars = delta; } }​ int n; do { //dst=0,cb.length - dst=8-0->n=8 n = in.read(cb, dst, cb.length - dst); } while (n == 0); if (n > 0) {//满足条件 //nChars=8 nChars = dst + n; //nextChar=0 nextChar = dst; } } }

第三次读取了两个字符到charsRead,把最后两个字符覆盖:fghijk

3、源码执行过程图解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章