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類添加行計數功能。至於這裏爲什麼不採用組合而使用繼承的方式來進行功能添加,在我看來是爲了提高代碼複用性,同時也由於該類的繼承關係不會大量修改纔會使用繼承關係來添加功能。

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