Java IO類庫之CharArrayReader

1、CharArrayReader的介紹

    CharArrayReader繼承自Reader,是Java字符輸入流的一種實現,它在內部維護了一個字符緩衝區用於保存讀取的字節數據,所以支持mark(標記)和reset(回滾)。java

2、CharArrayReader的成員變量

package java.io;

public class CharArrayReader extends Reader {
    /** 字符緩衝區 */
    protected char buf[];

    /**緩衝區數組buf下一個讀取的字符的下標 */
    protected int pos;

    /** 緩衝區buf中標記的下標位置 **/
    protected int markedPos = 0;

    /** 緩衝區中保存的字符個數  **/
    protected int count;

}

 

3、CharArrayReader源碼分析

1 - 構造函數

/**
     * 構造函數,指定字符緩衝區,初始化下一次讀取位置pos和有效字符個數count
     */
    public CharArrayReader(char buf[]) {
        this.buf = buf;
        this.pos = 0;
        this.count = buf.length;
    }

    /**
     * 構造函數,基於方法指定的字符數組buf,把數組起點offset做爲讀取的起點pos,數組長度-offset和length的較小值
     * 設置爲有效字符個數count     
     */
    public CharArrayReader(char buf[], int offset, int length) {
        //數組開始讀取起點offset和讀取長度length範圍校驗
        if ((offset < 0) || (offset > buf.length) || (length < 0) ||
            ((offset + length) < 0)) {
            throw new IllegalArgumentException();
        }
        this.buf = buf;
        this.pos = offset;
        this.count = Math.min(offset + length, buf.length);
        this.markedPos = offset;
    }

    經過對CharReader構造函數源碼分析,可知CharReader字符讀取的數據源保存在內部緩衝數組buf中,由CharReader實例化對象時構造函數的方法參數指定。第二個構造方法相對於第一個的區別在於它設置了讀取的初始位置pos爲方法指定參數offset數組

 

2 - 其餘成員方法

    本類的成員方法邏輯很簡單,以前參考下述的源碼註解理解。函數

/** 確認該字符輸入流CharReader還未關閉,方法主要是基於對內部緩衝區buf判空實現的  **/
    private void ensureOpen() throws IOException {
        if (buf == null)
            throw new IOException("Stream closed");
    }

    /**
     * 讀取一個字符
     */
    public int read() throws IOException {
        //加鎖
        synchronized (lock) {
            //檢測流是否已經關閉,即判斷緩衝區buf是否爲空
            ensureOpen();
            if (pos >= count)
                return -1;
            else
                return buf[pos++];
        }
    }

    /**
     * 將CharReader保存在字符緩衝區中的字符數據讀取到方法指定的字符數組,數組填充起點爲offset,填入的字符個數由
     * len和b.length-offset的最小值決定
     */
    public int read(char b[], int off, int len) throws IOException {
        synchronized (lock) {
            //流是否關閉
            ensureOpen();
            //數組字符填充起點offset和數組長度len範圍合法性校驗
            if ((off < 0) || (off > b.length) || (len < 0) ||
                ((off + len) > b.length) || ((off + len) < 0)) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {//讀取長度爲0直接結束返回
                return 0;
            }
            //當前字符輸入流字符數據已經所有讀取直接返回-1
            if (pos >= count) {
                return -1;
            }
            //當前字符流剩餘未讀取的字符個數小於方法指定要讀取的字節個數len,從新設置讀取字節個數爲剩餘未讀取字節個
            //數即count-pos
            if (pos + len > count) {
                len = count - pos;
            }
            
            if (len <= 0) {
                return 0;
            }
            //調用系統數組複製方法將緩衝區pos到pos+len範圍的字符數據複製到方法指定字符數組b中,從該數組起點off開
            //始填充字符數據
            System.arraycopy(buf, pos, b, off, len);
            //更新當前讀取下標pos
            pos += len;
            return len;
        }
    }

    /**
     * 跳過指定個數字符,若是方法指定跳過字符數參數n小於0則不作任何處理
     */
    public long skip(long n) throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (pos + n > count) {
                n = count - pos;
            }
            if (n < 0) {
                return 0;
            }
            pos += n;
            return n;
        }
    }

    /**
     * 判斷當前字符流是否已經準備好被讀取,主要是基於緩衝數組buf和當前讀取位置pos和可讀字節數count判斷
     */
    public boolean ready() throws IOException {
        synchronized (lock) {
            ensureOpen();
            return (count - pos) > 0;
        }
    }

    /**
     * 判斷CharReader是否支持mark()操做,返回true支持
     */
    public boolean markSupported() {
        return true;
    }

    /**
     * 標記當前字符輸入流的讀取位置,後續調用reset方法會將流從新定位到該位置進行讀取,方法指定參數readAheadLimit本
     * 意是指定標記以後繼續讀取多少字符,流仍然保留該標記的字符讀取限制,但由於CharReader數據源即內部緩衝區會保留所
     * 有字符數據,因此該參數能夠忽略
     */
    public void mark(int readAheadLimit) throws IOException {
        synchronized (lock) {
            ensureOpen();
            markedPos = pos;
        }
    }

    /**
     * 重置讀取位置到上一次標記位置或者若是以前不曾標記則重置到流開頭位置讀取
     */
    public void reset() throws IOException {
        synchronized (lock) {
            ensureOpen();
            pos = markedPos;
        }
    }

    /**
     * 關閉流,實際就是把內部緩衝區數組置空
     */
    public void close() {
        buf = null;
    }
相關文章
相關標籤/搜索