zoukankan      html  css  js  c++  java
  • BufferedReader源码分析

    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;
      }
      
      

      初步总结下,以上完成了三件事

      1. 初始化Reader
      2. 创建StreamDecoder实例
      3. 创建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码一个一个的赋值给字符流。

  • 相关阅读:
    QtDBus快速入门
    论Qt容器与STL
    JS中的!=、== 、!==、===的用法和区别
    JS操作JSON总结
    select2使用方法总结
    Entity Framework插入数据报错:Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
    Windows登录类型及安全日志解析
    <script type="text/html"></script> js模版使用
    在 C# 中,(int) ,Int32.Parse() 和 Convert.toInt32() 三种方法的区别
    关于session,cookie,Cache
  • 原文地址:https://www.cnblogs.com/cwhan/p/13975375.html
Copyright © 2011-2022 走看看