Java IO筆記(StringReader/StringWriter)


(最近剛來到簡書平臺询枚,以前在CSDN上寫的一些東西腿箩,也在逐漸的移到這兒來,有些篇幅是很早的時候?qū)懴碌墓统眩虼丝赡軙吹揭恍﹥?nèi)容雜亂的文章贷祈,對此深感抱歉,以下為正文)


正文

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

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

StringReader.java

package java.io;
 
public class StringReader extends Reader {
 
    //內(nèi)置了一個String類型的變量粟耻,用于存儲讀取的內(nèi)容。因為Reader只需要讀取無需對數(shù)據(jù)進行改變眉踱,所以此時一個String類型變量就已經(jīng)足夠了挤忙。
    private String str;
    //定義了3個int型變量,length表示讀取的字符串數(shù)據(jù)的長度谈喳,next表示下一個要讀取的位置册烈,mark表示標記的位置。
    private int length;
    private int next = 0;
    private int mark = 0;
 
    /**
     * 一個帶一個參數(shù)的構(gòu)造方法婿禽,傳入的參數(shù)是一個String類型數(shù)據(jù)赏僧,通過s初始化內(nèi)置的str和length屬性大猛。
     */
    public StringReader(String s) {
        this.str = s;
        this.length = s.length();
    }
 
    /** 
     * 該方法用于判斷當前流是否處于開啟狀態(tài),本質(zhì)就是檢測內(nè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索引結(jié)合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ù)的總長度攻人,表示此時已經(jīng)無數(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();
        //如果當前讀取的位置已經(jīng)位于讀取數(shù)據(jù)的末尾或者已經(jīng)超過了數(shù)據(jù)總長度,那么直接返回0坝橡,因為此時已經(jīng)無法再跳過數(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方法捌肴,關(guān)閉當前流,將內(nèi)置的str指向null藕咏。
     */
    public void close() {
        str = null;
    }
}

StringWriter.java

package java.io;
 
public class StringWriter extends Writer {
    //內(nèi)置了一個StringBuffer状知,因為這里牽扯到了數(shù)據(jù)的改變,所以簡單的String類型并不能滿足我們。
    private StringBuffer buf;
 
    /**
     * 一個不帶參的構(gòu)造函數(shù),內(nèi)部為buf進行了初始化辩昆,并將該緩存區(qū)作為了內(nèi)置鎖對象蛋济。
     */
    public StringWriter() {
        buf = new StringBuffer();
        lock = buf;
    }
 
    /**
     * 一個帶一個參數(shù)的構(gòu)造函數(shù)西设,傳入的參數(shù)為一個int型值瓣铣,該值決定了內(nèi)置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;
    }
 
    /**
     * 將內(nèi)置緩存區(qū)中的數(shù)據(jù)裝換為String類型并返回从橘。
     */
    public String toString() {
        return buf.toString();
    }
 
    /**
     * 返回內(nèi)置的StringBuffer對象。
     */
    public StringBuffer getBuffer() {
        return buf;
    }
 
    /**
     * 該方法本是將緩存中的數(shù)據(jù)強制寫出础钠,在本類是一個空實現(xiàn)恰力。
     */
    public void flush() {
    }
 
    /**
     * 該方法本市用于關(guān)閉流及釋放流相關(guān)聯(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);
            }
            //這里展示了即使關(guān)閉了StringWriter流驻民,但仍然能獲取到數(shù)據(jù)翻具,因為其close方法是一個空實現(xiàn)履怯。
            sw.close();
            System.out.println(sw.getBuffer().toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

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

以上為本篇的全部內(nèi)容槽畔。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末栈妆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鳞尔,老刑警劉巖嬉橙,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異寥假,居然都是意外死亡市框,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門糕韧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枫振,“玉大人,你說我怎么就攤上這事兔沃〗茫” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵乒疏,是天一觀的道長额衙。 經(jīng)常有香客問我,道長怕吴,這世上最難降的妖魔是什么窍侧? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮转绷,結(jié)果婚禮上伟件,老公的妹妹穿的比我還像新娘。我一直安慰自己议经,他們只是感情好斧账,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著煞肾,像睡著了一般咧织。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上籍救,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天习绢,我揣著相機與錄音,去河邊找鬼蝙昙。 笑死闪萄,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的奇颠。 我是一名探鬼主播败去,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烈拒!你這毒婦竟也來了圆裕?” 一聲冷哼從身側(cè)響起三椿,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎葫辐,沒想到半個月后搜锰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡耿战,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年蛋叼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剂陡。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡狈涮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸭栖,到底是詐尸還是另有隱情歌馍,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布晕鹊,位于F島的核電站松却,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏溅话。R本人自食惡果不足惜晓锻,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望飞几。 院中可真熱鬧砚哆,春花似錦、人聲如沸屑墨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卵史。三九已至战转,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間程腹,已是汗流浹背匣吊。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工儒拂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留寸潦,地道東北人。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓社痛,卻偏偏與公主長得像见转,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蒜哀,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容