BufferedReader

像BufferedInputStream为FileInputStream提供了缓冲区一样,BufferedReader为InputStreamReader提供了缓冲区。一般情况下,所有的读取都是先从下层输入流读取到缓冲区,然后再从缓冲区读取到目标数组,除非出现要读取的长度超过了缓冲区大小且缓冲区没有有效数据和有效mark,可以直接从下层输入流读取字符。

来看一下这个类的头部注释:从字符输入流读取文本,缓冲字符来提供高效地读取字符、数组和行。缓冲区的大小可能是指定的或者是默认大小,默认大小对于大部分情况足够大了。一般来说,Reader的每一个读取请求引起一个下层的字节或者字符输入流的读取请求。所以建议用BufferedReader来包裹一个read方法花费大的Reader,比如FileReaders和InputStreamReaders。例如 BufferedReader in = new BufferedReader(new FileReader("foo.in"));将会缓存从特定文件来的输入。没有缓冲,每一次调用read()或者readLine()可能引起从文件读取字节,转换为字符后返回,这样效率不高。使用DataInputStreams进行文本输入的程序可以通过替换每一个DataInputStream为合适的BufferedReader进行局部化。

前面已经解释过为什么可以通过从文件读取大块内容存储到内存缓冲区来提高整体读取速度,BufferedReader就是字符缓冲输入流。它提供了一个字符数组来作为缓冲区,默认大小是8K,在构造时初始化,fill()方法可能会出现需要重新分配一个更大数组的情况。从构造函数和内部变量中,我们可以看到它也具有内部包裹的下层输入流并且需要是Reader及其子类。

/**
     * 下层输入流
     */
    private Reader in;
    /**
     * 缓冲区
     */
    private char cb[];
    /**
     * 最后一个有效字符的位置
     */
    private int nChars;
    /**
     * 下一个要读取的字符位置
     */
    private int nextChar;

    private static final int INVALIDATED = -2;
    private static final int UNMARKED = -1;
    /**
     * 标记的位置,小于等于-1时代表不存在mark
     */
    private int markedChar = UNMARKED;
    private int readAheadLimit = 0; /* 只有markedChar > 0时是有效的 */

    /** 如果下一个字符是换行符,跳过它 */
    private boolean skipLF = false;

    /** 设定mark时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;
    }

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

ensureOpen这个内部方法的作用就是检查流有没有被关闭,标志是下层输入流为null