BufferedReader源码分析

BufferedReader源码分析

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] == ' ') {
               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,满足条件
           /* No mark */
           dst = 0;//初始化dst
      } 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 {
           //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] == ' ') {
               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] == ' ') {
               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,满足条件
           /* No mark */
           dst = 0;//初始化dst
      } 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 {
           //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、源码执行过程图解

 

记得快乐
原文地址:https://www.cnblogs.com/Y-wee/p/13426042.html