(最近剛來到簡書平臺询枚,以前在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)容槽畔。