JDK1.8源码学习--io包(BufferedReader)

前言
 

月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂)

央是一片海洋,海乃百川,代表着一块海绵(吸纳万物)

泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出)

月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容

希望大家一起坚持这个过程,也同样希望大家最终都能从零到零,把知识从薄变厚,再由厚变薄!
 

一.BufferedReader的作用:


         直接看源码注释(我的翻译可能不太准,如果道友们有更棒的理解,可以留言或者私信)
 

/**
 * Reads text from a character-input stream, buffering characters so as to
 * provide for the efficient reading of characters, arrays, and lines.
 * 1.从字符输入流中读取文本,缓冲字符以提供对字符、数组和行的有效读取。
 * <p> The buffer size may be specified, or the default size may be used.  The
 * default is large enough for most purposes.
 * 2.可以指定缓冲区大小,也可以使用默认大小。对于大多数用途,默认值足够大
 * <p> In general, each read request made of a Reader causes a corresponding
 * read request to be made of the underlying character or byte stream.  It is
 * therefore advisable to wrap a BufferedReader around any Reader whose read()
 * operations may be costly, such as FileReaders and InputStreamReaders.  For
 * example,
 *
 * <pre>
 * BufferedReader in
 *   = new BufferedReader(new FileReader("foo.in"));
 * </pre>
 * 3.通常,Reader 发出的每个读取请求都会导致对底层字符或字节流发出相应的读取请求。
 * 因此,建议将 BufferedReader 包装在任何 read() 操作可能代价高昂的 Reader 周围,
 * 例如 FileReaders 和 InputStreamReaders。
 * 例如, BufferedReader in = new BufferedReader(new FileReader("foo.in"));
 * 将缓冲来自指定文件的输入。如果没有缓冲,每次调用 read() 或 readLine() 都可能导致从文件中读取字节,
 * 转换为字符,然后返回,这可能非常低效
 * will buffer the input from the specified file.  Without buffering, each
 * invocation of read() or readLine() could cause bytes to be read from the
 * file, converted into characters, and then returned, which can be very
 * inefficient.
 *
 * <p> Programs that use DataInputStreams for textual input can be localized by
 * replacing each DataInputStream with an appropriate BufferedReader.
 * 4.使用 DataInputStreams 进行文本输入的程序可以通过用适当的 BufferedReader 替换每个 DataInputStream 来本地化
 * @see FileReader
 * @see InputStreamReader
 * @see java.nio.file.Files#newBufferedReader
 *
 * @author      Mark Reinhold
 * @since       JDK1.1
 */

二.类图:

 三.成员变量: 

        

    private Reader in;

    private char cb[];
    private int nChars, nextChar;

    private static final int INVALIDATED = -2;
    private static final int UNMARKED = -1;
    private int markedChar = UNMARKED;
    private int readAheadLimit = 0; /* Valid only when markedChar > 0  仅在标记字符 > 0 时有效 */

    /** If the next character is a line feed, skip it  如果下一个字符是换行符,则跳过它*/
    private boolean skipLF = false;

    /** The skipLF flag when the mark was set  设置标记时的 skipLF 标志*/
    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;
        cb = new char[sz];
        nextChar = nChars = 0;
    }

    /**
     * 创建一个使用默认大小的输入缓冲区的缓冲字符输入流。
     */
    public BufferedReader(Reader in) {
        this(in, defaultCharBufferSize);
    }

五.内部方法:  

                fill

    /**
     * 填充输入缓冲区,考虑标记是否有效
     */
    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 {
            n = in.read(cb, dst, cb.length - dst);
        } while (n == 0);
        if (n > 0) {
            nChars = dst + n;
            nextChar = dst;
        }
    }

                read

    /**
     * 读取单个字符。
     */
    public int read() throws IOException {
        synchronized (lock) {
            ensureOpen();
            for (;;) {
                if (nextChar >= nChars) {
                    fill();
                    if (nextChar >= nChars)
                        return -1;
                }
                if (skipLF) {
                    skipLF = false;
                    if (cb[nextChar] == '\n') {
                        nextChar++;
                        continue;
                    }
                }
                return cb[nextChar++];
            }
        }
    }

    /**
     * 将字符读入数组的一部分,必要时从底层流中读取
     */
    private int read1(char[] cbuf, int off, int len) throws IOException {
        if (nextChar >= nChars) {
            /* If the requested length is at least as large as the buffer, and
               if there is no mark/reset activity, and if line feeds are not
               being skipped, do not bother to copy the characters into the
               local buffer.  In this way buffered streams will cascade
               harmlessly.
               如果请求的长度至少与缓冲区一样大,并且没有标记重置活动,并且没有跳过换行符,
               则不要费心将字符复制到本地缓冲区中。这样缓冲的流将无害地级联*/
            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;
            }
        }
        int n = Math.min(len, nChars - nextChar);
        System.arraycopy(cb, nextChar, cbuf, off, n);
        nextChar += n;
        return n;
    }

    /**
     * 1.将字符读入数组的一部分。
     * 2.该方法实现了Reader类对应的Reader.read(char[], int, int)方法的通用约定。
     * 作为额外的便利,它尝试通过重复调用底层流的read方法来读取尽可能多的字符
     * 3.这个迭代的read一直持续到以下条件之一变为真:
     * 指定数量的字符已被读取,
     * 底层流的read方法返回-1,表示文件结束,或者底层流的ready方法返回false,表示进一步的输入请求会阻塞
     * 4.如果底层流上的第一个read返回-1以指示文件结束,则此方法返回-1。否则此方法返回实际读取的字符数。
     * 5.鼓励但不要求此类的子类尝试以相同的方式读取尽可能多的字符

     * 6.通常,此方法从该流的字符缓冲区中获取字符,并根据需要从底层流填充它。但是,如果缓冲区为空,标记无效,
     * 并且请求的长度至少与缓冲区一样大,则此方法将直接从底层流读取字符到给定的数组中。
     * 因此冗余的BufferedReader不会不必要地复制数据。
     */
    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;
            }

            int n = read1(cbuf, off, len);
            if (n <= 0) return n;
            while ((n < len) && in.ready()) {
                int n1 = read1(cbuf, off + n, len - n);
                if (n1 <= 0) break;
                n += n1;
            }
            return n;
        }
    }

    /**
     * 读取一行文本。一行被视为以换行符 ('\n')、回车符 ('\r') 或回车符后紧跟换行符中的任何一个结束
     * @param      ignoreLF  If true, the next '\n' will be skipped 如果为真,下一个 '\n' 将被跳过
     */
    String readLine(boolean ignoreLF) throws IOException {
        StringBuffer s = null;
        int startChar;

        synchronized (lock) {
            ensureOpen();
            boolean omitLF = ignoreLF || skipLF;

        bufferLoop:
            for (;;) {

                if (nextChar >= nChars)
                    fill();
                if (nextChar >= nChars) { /* EOF */
                    if (s != null && s.length() > 0)
                        return s.toString();
                    else
                        return null;
                }
                boolean eol = false;
                char c = 0;
                int i;

                /* Skip a leftover '\n', if necessary */
                if (omitLF && (cb[nextChar] == '\n'))
                    nextChar++;
                skipLF = false;
                omitLF = false;

            charLoop:
                for (i = nextChar; i < nChars; i++) {
                    c = cb[i];
                    if ((c == '\n') || (c == '\r')) {
                        eol = true;
                        break charLoop;
                    }
                }

                startChar = nextChar;
                nextChar = i;

                if (eol) {
                    String str;
                    if (s == null) {
                        str = new String(cb, startChar, i - startChar);
                    } else {
                        s.append(cb, startChar, i - startChar);
                        str = s.toString();
                    }
                    nextChar++;
                    if (c == '\r') {
                        skipLF = true;
                    }
                    return str;
                }

                if (s == null)
                    s = new StringBuffer(defaultExpectedLineLength);
                s.append(cb, startChar, i - startChar);
            }
        }
    }

    /**
     * 读取一行文本。一行被视为以换行符 ('\n')、回车符 ('\r') 或回车符后紧跟换行符中的任何一个结束
     */
    public String readLine() throws IOException {
        return readLine(false);
    }

                skip

    /**
     * 跳过字符。
     * @param  n  The number of characters to skip 要跳过的字符数
     */
    public long skip(long n) throws IOException {
        if (n < 0L) {
            throw new IllegalArgumentException("skip value is negative");
        }
        synchronized (lock) {
            ensureOpen();
            long r = n;
            while (r > 0) {
                if (nextChar >= nChars)
                    fill();
                if (nextChar >= nChars) /* EOF */
                    break;
                if (skipLF) {
                    skipLF = false;
                    if (cb[nextChar] == '\n') {
                        nextChar++;
                    }
                }
                long d = nChars - nextChar;
                if (r <= d) {
                    nextChar += r;
                    r = 0;
                    break;
                }
                else {
                    r -= d;
                    nextChar = nChars;
                }
            }
            return n - r;
        }
    }

                ready

    /**
     * 告诉这个流是否准备好被读取。如果缓冲区不为空,或者基础字符流已准备好,则缓冲字符流已准备好。
     */
    public boolean ready() throws IOException {
        synchronized (lock) {
            ensureOpen();

            /*
             * If newline needs to be skipped and the next char to be read
             * is a newline character, then just skip it right away.
             * 如果需要跳过换行符并且要读取的下一个字符是换行符,则立即跳过它
             */
            if (skipLF) {
                /* Note that in.ready() will return true if and only if the next
                 * read on the stream will not block.
                 * 请注意,当且仅当对流的下一次读取不会阻塞时,in.ready() 才会返回 true。
                 */
                if (nextChar >= nChars && in.ready()) {
                    fill();
                }
                if (nextChar < nChars) {
                    if (cb[nextChar] == '\n')
                        nextChar++;
                    skipLF = false;
                }
            }
            return (nextChar < nChars) || in.ready();
        }
    }

                mark

    /**
     * 告诉这个流是否支持 mark() 操作,它支持
     */
    public boolean markSupported() {
        return true;
    }

    /**
     * 标记流中的当前位置。对 reset() 的后续调用将尝试将流重新定位到这一点。
     * @param readAheadLimit   Limit on the number of characters that may be
     *                         read while still preserving the mark. An attempt
     *                         to reset the stream after reading characters
     *                         up to this limit or beyond may fail.
     *                         A limit value larger than the size of the input
     *                         buffer will cause a new buffer to be allocated
     *                         whose size is no smaller than limit.
     *                         Therefore large values should be used with care.
     *限制在保留标记的同时可以读取的字符数。在读取达到或超过此限制的字符后尝试重置流可能会失败。
     *                         大于输入缓冲区大小的限制值将导致分配大小不小于限制的新缓冲区。因此,应谨慎使用较大的值
     */
    public void mark(int readAheadLimit) throws IOException {
        if (readAheadLimit < 0) {
            throw new IllegalArgumentException("Read-ahead limit < 0");
        }
        synchronized (lock) {
            ensureOpen();
            this.readAheadLimit = readAheadLimit;
            markedChar = nextChar;
            markedSkipLF = skipLF;
        }
    }

                reset

    /**
     *将流重置为最近的标记。
     */
    public void reset() throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (markedChar < 0)
                throw new IOException((markedChar == INVALIDATED)
                                      ? "Mark invalid"
                                      : "Stream not marked");
            nextChar = markedChar;
            skipLF = markedSkipLF;
        }
    }

                close

public void close() throws IOException {
        synchronized (lock) {
            if (in == null)
                return;
            try {
                in.close();
            } finally {
                in = null;
                cb = null;
            }
        }
    }

                lines

    /**
     * 1.返回一个Stream,其元素是从此BufferedReader读取的行。Stream是惰性填充的,
     * 即只读发生在终端流操作期间。
     * 2.在终端流操作的执行过程中,阅读器不能被操作。否则,终端流操作的结果是未定义的
     * 3.执行终端流操作后,无法保证读取器将位于特定位置,从该位置读取下一个字符或行。
     * 4.如果在访问底层 BufferedReader时抛出IOException,它会被包装在一个UncheckedIOException中,
     * 该异常将从导致读取发生的Stream方法抛出。如果在关闭的 BufferedReader 上调用此方法将返回一个 Stream。
     * 在该流关闭后需要从 BufferedReader 读取的任何操作都将导致抛出 UncheckedIOException。
     */
    public Stream<String> lines() {
        Iterator<String> iter = new Iterator<String>() {
            String nextLine = null;

            @Override
            public boolean hasNext() {
                if (nextLine != null) {
                    return true;
                } else {
                    try {
                        nextLine = readLine();
                        return (nextLine != null);
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                }
            }

            @Override
            public String next() {
                if (nextLine != null || hasNext()) {
                    String line = nextLine;
                    nextLine = null;
                    return line;
                } else {
                    throw new NoSuchElementException();
                }
            }
        };
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
    }

六.总结:

        io流分支还是非常之多的,等全部看完源码,也要单独出一章来总结一下...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值