Java 日看一类 (33)之IO包中的LineNumberReader类

该类无引入包

继承自BufferedReader



类头注释如下:

/**
 * A buffered character-input stream that keeps track of line numbers.  This
 * class defines methods {@link #setLineNumber(int)} and {@link
 * #getLineNumber()} for setting and getting the current line number
 * respectively.
 *
 * <p> By default, line numbering begins at 0. This number increments at every
 * <a href="#lt">line terminator</a> as the data is read, and can be changed
 * with a call to <tt>setLineNumber(int)</tt>.  Note however, that
 * <tt>setLineNumber(int)</tt> does not actually change the current position in
 * the stream; it only changes the value that will be returned by
 * <tt>getLineNumber()</tt>.
 *
 * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
 * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
 * immediately by a linefeed.
 *
 * @author      Mark Reinhold
 * @since       JDK1.1
 */

大意如下:

该类是可记录行号的缓冲字符输出流

该类声明了方法setLineNumber()和getLineNumber()来设置和获得当前的行号

默认情况下,行号从0开始

行号随数据中行结束符的读取而增加,也可以被setLineNumber()方法修改

注意,无论如何setLineNumber都不会修改流中的当前读取标识位,仅仅改变getLineNumber的返回值

一行可以认为在遇到以下符号结束,换行符'\n',回车符'\r',或者是回车后紧跟换行符



该类含有如下的成员变量:

当前的行计数值:

private int lineNumber = 0;

被标记的行计数值:

private int markedLineNumber;

跳过下个换行符标志位:(必须是下个字符恰好为换行符

private boolean skipLF;

标记点的跳过换行符标志位状态

private boolean markedSkipLF;

最大缓冲区

private static final int maxSkipBufferSize = 8192;

跳过值的缓冲区数组(垃圾场)

private char skipBuffer[] = null;


该类含有如下的成员方法:

构造函数(给一个reader加上行计数功能

public LineNumberReader(Reader in) {
    super(in);
}

构造函数(设立缓冲区大小

public LineNumberReader(Reader in, int sz) {
    super(in, sz);
}

设置当前行计数值

public void setLineNumber(int lineNumber) {
    this.lineNumber = lineNumber;
}

获得行计数值

public int getLineNumber() {
    return lineNumber;
}

覆写的read(),读取单个字符(加了行计数功能

public int read() throws IOException {
    synchronized (lock) {
        int c = super.read();
        if (skipLF) {//如果需要跳过下个换行符
            if (c == '\n')
                c = super.read();//继续读取
            skipLF = false;
        }
        switch (c) {
        case '\r':
            skipLF = true;//若为回车符就跳过下个换行符,同时++行数
        case '\n':          /* Fall through */
            lineNumber++;
            return '\n';//直接返回换行符
        }
        return c;
    }
}

覆写的read(char[],int,int),将字符读取入传入的数组特定位置

public int read(char cbuf[], int off, int len) throws IOException {
    synchronized (lock) {
        int n = super.read(cbuf, off, len);//n为实际读取数

        for (int i = off; i < off + n; i++) {//遍历读取入的数组
            int c = cbuf[i];
            if (skipLF) {
                skipLF = false;
                if (c == '\n')//直接跳过下面选择继续读取计数
                    continue;
            }
            switch (c) {
            case '\r':
                skipLF = true;
            case '\n':      /* Fall through */
                lineNumber++;
                break;
            }
        }

        return n;
    }
}

覆写readLine(),读取一行数据

public String readLine() throws IOException {
    synchronized (lock) {
        String l = super.readLine(skipLF);//读取的一行数据,如果有跳过换行符实际读取是两行数据
        skipLF = false;
        if (l != null)
            lineNumber++;
        return l;
    }
}

跳过后续的数个字符进行读取

public long skip(long n) throws IOException {
    if (n < 0)
        throw new IllegalArgumentException("skip() value is negative");
    int nn = (int) Math.min(n, maxSkipBufferSize);//取较小值然后把需跳过数据读入到“垃圾场”中;
    synchronized (lock) {
        if ((skipBuffer == null) || (skipBuffer.length < nn))
            skipBuffer = new char[nn];//缓冲区初始化
        long r = n;
        while (r > 0) {
            int nc = read(skipBuffer, 0, (int) Math.min(r, nn));//重复向“垃圾场”中丢弃跳过数据
            if (nc == -1)//读取完毕
                break;
            r -= nc;//还需丢弃的垃圾数
        }
        return n - r;//返回实际跳过数据
    }
}

覆写标记点操作,标记当前读入位置

public void mark(int readAheadLimit) throws IOException {
    synchronized (lock) {
        super.mark(readAheadLimit);//最大回溯距离
        markedLineNumber = lineNumber;
        markedSkipLF     = skipLF;
    }
}

回滚操作(读取指针回归到标记位置,各种标志位也回归当时状态

public void reset() throws IOException {
    synchronized (lock) {
        super.reset();
        lineNumber = markedLineNumber;
        skipLF     = markedSkipLF;
    }
}



该类相当于是对BufferedReader类做了一个小升级,采用的是继承的方式来向BufferedReader类添加行计数功能。至于这里为什么不采用组合而使用继承的方式来进行功能添加,在我看来是为了提高代码复用性,同时也由于该类的继承关系不会大量修改才会使用继承关系来添加功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章