java源码-BufferedReader

开篇

 在设计模式中有一种叫做装饰者模式,刚好BufferedReader的源码是这个设计模式的最好例子,一并看下源码。


源码分析

构造函数

  • BufferedReader的类变量的Reader in 用以构造函数参数中的Reader in参数,BufferedReader的所有读写操作都通过Reader对象进行操作。
  • BufferedReader相当于针对内部的Reader对象进行了一层包装,可以理解为装饰者。
public class BufferedReader extends Reader {
    private Reader in;
    private char cb[];
    //nextChar代表下次要读取的位置,nChars表示总共的字符个数
    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 */
    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;
        cb = new char[sz];
        nextChar = nChars = 0;
    }

    public BufferedReader(Reader in) {
        this(in, defaultCharBufferSize);
    }
}



加载数据

  • 负责通过Reader in对象读取字符到指定数量的字符数据到cb数组当中。
  • dst表示保存数据的起始位置,cb.length-dst表示读取字符的个数。
  • 在执行read和readline操作的之前如果cb当中可读字符不足会先执行fill()读取字符。
 private void fill() throws IOException {
        int dst;
        if (markedChar <= UNMARKED) {
            /* No mark */
            dst = 0;
        } else {
            // 省略一部分代码
        }

        int n;
        do {
            // 从底层input读取数据到cb,cb中起始位置是dst, 
            // 读取的长度是cb的lenght减去起始位置dst,理解剩余能够装的字符
            n = in.read(cb, dst, cb.length - dst);
        } while (n == 0);
        if (n > 0) {
            // 设置最大可读字符结束位置
            nChars = dst + n;
            // 设置可读字符的起始位置
            nextChar = dst;
        }
    }



read过程

  • 读取过程中如果满足条件(nextChar 表示下一个读取字符>= nChars可用字符),代表字符已经读取完毕那么就通过fill()进行预加载。
  • 读取当前字符并累加当前可读取字符,执行nextChar++操作。
    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++];
            }
        }
    }



readline过程

  • 读取过程中如果满足条件(nextChar 表示下一个读取字符>= nChars可用字符),代表字符已经读取完毕那么就通过fill()进行预加载。
  • 读取过程中如果遇到\r\n则中断循环,通过str = new String(cb, startChar, i - startChar)返回整行数据。
    String readLine(boolean ignoreLF) throws IOException {
        //读取的数据最终放在这个s中,
        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)
                        //从这里返回,可能是因为读取的数据最后没有以\n或\r结束
                        return s.toString();
                    else
                        // 从这里返回,是因为开始读的时候,就已经是input的末尾了,
                        // 所以s本身就没有被初始化,只能返回null
                        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;
                    // 运行到这,s为null,说明是第一次循环中就读到了行尾。
                    if (s == null) {
                        str = new String(cb, startChar, i - startChar);
                    } else {
                        // 运行到这,起码说明是第二次循环了,s里已经有了第一次读取的数据
                        s.append(cb, startChar, i - startChar);
                        str = s.toString();
                    }
                    nextChar++;
                    if (c == '\r') {
                        skipLF = true;
                    }
                    // 运行到这说明读到了行尾,返回str
                    return str;
                }

                if (s == null)
                    s = new StringBuffer(defaultExpectedLineLength);
                // 运行到这说明,读取了整个cb的数据,发现一直没有\n或者\r, 
                // 之后回到最初循环继续读取。
                s.append(cb, startChar, i - startChar);
            }
        }
    }


类依赖图

  • BufferedReader的类依赖图如下图,所有的io reader都是继承自Reader作为基类。


    java源码-BufferedReader_第1张图片


装饰设计模式

装饰设计模式:javaIO技术中的装饰设计模式,对一组对象的功能进行增强时,就可以使用该设计模式

你可能感兴趣的:(java源码-BufferedReader)