• 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
Copyright © 2020-2023  润新知