Java IO筆記(StringReader/StringWriter)


(最近剛來到簡書平臺,以前在CSDN上寫的一些東西,也在逐漸的移到這兒來,有些篇幅是很早的時候寫下的,因此可能會看到一些內容雜亂的文章,對此深感抱歉,以下為正文)


正文

本篇將要講述的是Java IO包中的StringReader和StringWriter類。這兩個類都是Reader和Writer的裝飾類,使它們擁有了對String類型數(shù)據(jù)進行操作的能力。

下面還是先附上源碼,然后對其進行簡單的分析:

StringReader.java

package java.io;
 
public class StringReader extends Reader {
 
    //內置了一個String類型的變量,用于存儲讀取的內容。因為Reader只需要讀取無需對數(shù)據(jù)進行改變,所以此時一個String類型變量就已經足夠了。
    private String str;
    //定義了3個int型變量,length表示讀取的字符串數(shù)據(jù)的長度,next表示下一個要讀取的位置,mark表示標記的位置。
    private int length;
    private int next = 0;
    private int mark = 0;
 
    /**
     * 一個帶一個參數(shù)的構造方法,傳入的參數(shù)是一個String類型數(shù)據(jù),通過s初始化內置的str和length屬性。
     */
    public StringReader(String s) {
        this.str = s;
        this.length = s.length();
    }
 
    /** 
     * 該方法用于判斷當前流是否處于開啟狀態(tài),本質就是檢測內置的str是否被賦值。
     */
    private void ensureOpen() throws IOException {
        if (str == null)
            throw new IOException("Stream closed");
    }
 
    /**
     * 每次讀取一個字符的read方法,最終返回讀取字符的int值。
     */
    public int read() throws IOException {
        synchronized (lock) {
        //進行操作前,確保當前流處于開啟狀態(tài)。
            ensureOpen();
        //如果讀取的位置,超過了數(shù)據(jù)的總長度,那么直接返回-1,表示已無數(shù)據(jù)可讀。
            if (next >= length)
                return -1;
        //正常情況下通過next索引結合String類型的charAt方法,來從str中取出對應的字符數(shù)據(jù)。
            return str.charAt(next++);
        }
    }
 
    /**
     * 每次讀入多個字符的read方法,最終返回實際讀取的字符個數(shù)。該方法有3個參數(shù),第一個參數(shù)為一個字符數(shù)組,用于存儲讀取的數(shù)據(jù),第二和第三個參數(shù)為一個int
     * 變量,分別為開始在數(shù)組中存儲數(shù)據(jù)的起點和存儲數(shù)據(jù)的長度。
     */
    public int read(char cbuf[], int off, int len) throws IOException {
        synchronized (lock) {
        //進行操作前需要先判斷當前流是否處于開啟狀態(tài)。
            ensureOpen();
        //對傳入的參數(shù)進行安全檢測,如果不合法則拋出相應異常。
            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
                ((off + len) > cbuf.length) || ((off + len) < 0)) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return 0;
            }
        //如果下一個讀取的位置超過了讀取的數(shù)據(jù)的總長度,表示此時已經無數(shù)據(jù)可讀,此時直接返回-1。
            if (next >= length)
                return -1;
        //定義了一個int型值n,用來接收length-next和len之間的較小值,一般情況下使用len即可,如果len長度超過了數(shù)據(jù)的總長度,那么就使用length-next的值。
            int n = Math.min(length - next, len);
        //使用String類的getChars方法,將指定str從next到next+n位置的數(shù)據(jù)拷貝到傳入cbuf中,拷貝位置從off開始。
            str.getChars(next, next + n, cbuf, off);
        //數(shù)據(jù)讀取拷貝完畢后,將下一個讀取的位置向后移位n位,最后返回n,即實際讀取的數(shù)據(jù)長度。
            next += n;
            return n;
        }
    }
 
    /**
     * 該方法用于跳過指定長度的數(shù)據(jù)。
     */
    public long skip(long ns) throws IOException {
        synchronized (lock) {
        //進行操作前先確定當前流是否處于開啟狀態(tài)。
            ensureOpen();
        //如果當前讀取的位置已經位于讀取數(shù)據(jù)的末尾或者已經超過了數(shù)據(jù)總長度,那么直接返回0,因為此時已經無法再跳過數(shù)據(jù)進行讀取了。
            if (next >= length)
                return 0;
            //定義了一個long型數(shù)據(jù)n用來存放length-next和ns之間的較小值,一般情況下是ns起作用,如果ns超過了當前未讀取的數(shù)據(jù)總長度,那么使用length-next。
            long n = Math.min(length - next, ns);
        //這里是為了處理傳入的ns是負數(shù)的情況,當傳入的值為負數(shù)時,此時讀取位置應當向回移動,在上一布操作中如果傳入的ns為負數(shù)的話,那么此時的n必定是ns
        //Math.max(-next,n)則保證了只有只有當讀取位置大于回讀的數(shù)量時才可以回讀,所以最多之能回退到數(shù)據(jù)的起點位置。
            n = Math.max(-next, n);
        //下一次讀取的位置移動n個位置,最終將n返回。
            next += n;
            return n;
        }
    }
 
    /**
     * 該方法用于判斷當前流是否處于可讀狀態(tài)。
     */
    public boolean ready() throws IOException {
        synchronized (lock) {
        ensureOpen();
        return true;
        }
    }
 
    /**
     * 該方法用于判斷當前流是否支持流標記功能。
     */
    public boolean markSupported() {
        return true;
    }
 
    /**
     * 該方法用于在指定位置留下流標記,與reset方法連用,可以試當前讀取位置回退到在流中的標記位置
     */
    public void mark(int readAheadLimit) throws IOException {
    //對傳入的參數(shù)進行安全檢測,標記的位置不能小于0,否則拋出相應的異常。
        if (readAheadLimit < 0){
            throw new IllegalArgumentException("Read-ahead limit < 0");
        }
        synchronized (lock) {
        //在進行操作前,確定當前流處于開啟狀態(tài)。
            ensureOpen();
        //使用mark變量記錄下當前讀取的位置。
            mark = next;
        }
    }
 
    /**
     * 該方法用于將當前讀取位置回退到流中的標記位置。
     */
    public void reset() throws IOException {
        synchronized (lock) {
        //在進行操作前,確定當前流是否處于開啟狀態(tài)。然后將當前讀取位置回退到mark處。
            ensureOpen();
            next = mark;
        }
    }
 
    /**
     * close方法,關閉當前流,將內置的str指向null。
     */
    public void close() {
        str = null;
    }
}

StringWriter.java

package java.io;
 
public class StringWriter extends Writer {
    //內置了一個StringBuffer,因為這里牽扯到了數(shù)據(jù)的改變,所以簡單的String類型并不能滿足我們。
    private StringBuffer buf;
 
    /**
     * 一個不帶參的構造函數(shù),內部為buf進行了初始化,并將該緩存區(qū)作為了內置鎖對象。
     */
    public StringWriter() {
        buf = new StringBuffer();
        lock = buf;
    }
 
    /**
     * 一個帶一個參數(shù)的構造函數(shù),傳入的參數(shù)為一個int型值,該值決定了內置buf初始化時的容量大小。
     */
    public StringWriter(int initialSize) {
        if (initialSize < 0) {
            throw new IllegalArgumentException("Negative buffer size");
        }
        buf = new StringBuffer(initialSize);
        lock = buf;
    }
 
    /**
     * 該方法用于流中每次寫入一個字符。
     */
    public void write(int c) {
        buf.append((char) c);
    }
 
    /**
     * 該方法用于向流中每次寫入多個字節(jié)。
     */
    public void write(char cbuf[], int off, int len) {
        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
            ((off + len) > cbuf.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }
        buf.append(cbuf, off, len);
    }
 
    /**
     * 該方法每次向流中寫入一個字符串類型的數(shù)據(jù)。
     */
    public void write(String str) {
        buf.append(str);
    }
 
    /**
     * 該方法每次向流中寫入一個字符串數(shù)據(jù)的一部分。
     */
    public void write(String str, int off, int len)  {
        buf.append(str.substring(off, off + len));
    }
 
    /**
     * 該方法基本等同于上面的write(String str)方法,可以將制定的字符序列寫入流中。
     */
    public StringWriter append(CharSequence csq) {
        if (csq == null)
            write("null");
        else
            write(csq.toString());
        return this;
    }
 
    /**
     * 可以將一個字符序列的一部分寫入流中,最后返回流本身。
     */
    public StringWriter append(CharSequence csq, int start, int end) {
        CharSequence cs = (csq == null ? "null" : csq);
        write(cs.subSequence(start, end).toString());
        return this;
    }
 
    /**
     * 可以將一個字符數(shù)據(jù)寫入流中的,最后返回流本身。
     */
    public StringWriter append(char c) {
        write(c);
        return this;
    }
 
    /**
     * 將內置緩存區(qū)中的數(shù)據(jù)裝換為String類型并返回。
     */
    public String toString() {
        return buf.toString();
    }
 
    /**
     * 返回內置的StringBuffer對象。
     */
    public StringBuffer getBuffer() {
        return buf;
    }
 
    /**
     * 該方法本是將緩存中的數(shù)據(jù)強制寫出,在本類是一個空實現(xiàn)。
     */
    public void flush() {
    }
 
    /**
     * 該方法本市用于關閉流及釋放流相關聯(lián)的系統(tǒng)資源,在本類是一個空實現(xiàn)。
     */
    public void close() throws IOException {
    }
 
}

通過上面對源碼的簡單分析,我們隊StringReader和StringWriter有了初步的認識,下面通過一個簡單的小例子來展示其用法。

package StringIO;
 
import java.io.StringReader;
import java.io.StringWriter;
 
public class StringIOTest {
    public static void main(String[] args) {
        try (StringReader sr = new StringReader("just a test~");
                StringWriter sw = new StringWriter()) {
            int c = -1;
            while((c = sr.read()) != -1){
                sw.write(c);
            }
            //這里展示了即使關閉了StringWriter流,但仍然能獲取到數(shù)據(jù),因為其close方法是一個空實現(xiàn)。
            sw.close();
            System.out.println(sw.getBuffer().toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

剛開始我是比較奇怪這兩個類為什么會存在的,因為這與直接使用String類來進行數(shù)據(jù)操作,后來在網上看到別人的解釋,如果你遇到一個情景是你必須使用一個Reader或者Writer來作為參數(shù)傳遞參數(shù),但你的數(shù)據(jù)源又僅僅是一個String類型數(shù)據(jù),無需從文件中寫出,那么此時就可以用到它們。并且值得注意的是StringWriter中,寫入的數(shù)據(jù)只是存在于緩存中,并不會寫入實質的存儲介質之中。

以上為本篇的全部內容。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容