Java?IO流之StringWriter和StringReader用法分析
簡介
StringWriter和StringReader分別繼承自Writer和Reader抽象類,作用就是將字符串String類型適配到StringWriter和StringReader類.
其中StringWriter實(shí)際上是用StringBuffer實(shí)現(xiàn)的,StringBuffer是一個(gè)線程安全的類,實(shí)際上默認(rèn)的是16個(gè)字符的char數(shù)組.所以通過方法write()和append()等其他重載的方法.將字符串添加到StringBuffer中,可以調(diào)用toString()或者getBuffer()方法顯示StringWriter流中所有的數(shù)據(jù).其中close()方法和flush()方法,無實(shí)際的功能,只是簡單的繼承.
StringReader的有參構(gòu)造方法傳入的是String類型的數(shù)據(jù),通過read()重載方法讀取流中部分或者全部的字符內(nèi)容.
StringWriter介紹
1.構(gòu)造方法
public StringWriter() {}
public StringWriter(int initialSize) {}
無參構(gòu)造方法,創(chuàng)建的是默認(rèn)大小為StringBuffer的StringWriter流,其中StringBuffer底層實(shí)際是一個(gè)字符數(shù)組,默認(rèn)大小是16個(gè)字符.
有參構(gòu)造方法,創(chuàng)建的是指定大小的StringBuffer的StringWriter流,也就是指定initialSize個(gè)字符的字符數(shù)組.
2.內(nèi)部變量
private StringBuffer buf;
StringWriter流中緩沖區(qū)實(shí)際上通過StringBuffer來實(shí)現(xiàn)的.
3. 內(nèi)部方法
public void write(int c) {}
public void write(char cbuf[], int off, int len){}
public void write(String str) {}
public void write(String str, int off, int len){}
public StringWriter append(CharSequence csq){}
public StringWriter append(CharSequence csq, int start, int end){}
public StringWriter append(char c){}
public String toString() {}
public StringBuffer getBuffer() {}
public void flush() {}
public void close() {}
write(int c)---將單個(gè)字符寫到流中.write(char cbuf[] ,int off,int len)---將字符數(shù)組cbuf中off開始,len個(gè)字符寫到流中.write(String str)---將字符串str寫到流中.write(String str,int off,int len)---將字符串str中off位置開始,len個(gè)字符寫到流中.append(charsequence csq)---將字符序列csq寫到流中.append(charsequence csq,int start ,int end)----將字符序列中start到end之間字符寫到流中.append(char c)---將單個(gè)字符寫到流中.toString()---將流中所有字符轉(zhuǎn)換成字符串返回.getBuffer()----將流中內(nèi)容,實(shí)際是StringBuffer返回.flush()---僅僅是繼承,方法內(nèi)沒有任何實(shí)現(xiàn).close()----僅僅是繼承,方法內(nèi)沒有任何實(shí)現(xiàn).
StringReader介紹
1.構(gòu)造方法
public StringReader(String s) {}
有參構(gòu)造方法,傳入的實(shí)際上是流中內(nèi)容為字符串s.
2.內(nèi)部變量
private String str; private int length; private int next = 0; private int mark = 0;
str---StringReader流中實(shí)際的數(shù)據(jù)就是通過構(gòu)造方法傳入的字符串str.length---流中字符串的長度.next---要讀取的下一個(gè)字符的位置.mark---標(biāo)記字符位置,調(diào)用mark()方法會將當(dāng)前位置保存到mark中.
3. 內(nèi)部方法
private void ensureOpen(){}
public int read(){}
public int read(char cbuf[], int off, int len){}
public long skip(long ns){}
public boolean ready(){}
public boolean markSupported() {}
public void mark(int readAheadLimit){}
public void reset(){}
public void close(){}
ensureOpen()---確保流沒有關(guān)閉,實(shí)際判斷是流中內(nèi)容字符串str不為null.read()---從流中讀取一個(gè)字符.read(char cbuf[],int off,int len)---將流中最多l(xiāng)en個(gè)字符讀取到字符數(shù)組cbuf中,cbuf中從off開始.skip(long ns)---跳過ns個(gè)字符.ready()---流是否準(zhǔn)備讀取.markSupported()---是否支持標(biāo)記mark(int readAheadLimit)---標(biāo)記當(dāng)前位置,readAheadLimit表示的是在標(biāo)記有效情況下,從當(dāng)前位置開始可取的最大字符數(shù).reset()---將流中當(dāng)前位置重置到標(biāo)記位置.close()---關(guān)閉流,實(shí)際上是將流中內(nèi)容字符串str置為null.
案例
public class StringWriterDemo {
public static void main(String[] args) throws IOException {
testStringWriter();
testStringReader();
testOfAnotherStringWriter();
}
//測試StringWriter
private static void testStringWriter() throws IOException {
StringWriter sw = new StringWriter();
sw.append("this is a");
sw.write("demo of StringWriter");
System.out.println(sw.toString());
sw.close();
}
//測試StringReader
private static void testStringReader() throws IOException {
String content = "this is a demo of StringReader";
StringReader sr = new StringReader(content);
int c;
while((c=sr.read())!=-1) {
System.out.println((char)c);
}
sr.close();
}
//將讀取的數(shù)據(jù)先寫到StringWriter流中,然后直接調(diào)用toString()方法打印結(jié)果
private static void testOfAnotherStringWriter() throws IOException {
FileReader fr = new FileReader("D:\\java.txt");
BufferedReader br = new BufferedReader(fr);
StringWriter sw = new StringWriter();
int n;
char cbuf[] = new char[1024];
while((n=br.read(cbuf))!=-1) {
sw.write(cbuf, 0, n);
}
System.out.println(sw.toString());
fr.close();
br.close();
}
}
源碼分析
1.StringWriter源碼分析
public class StringWriter extends Writer {
//StringWriter中緩沖功能是通過StringBuffer來實(shí)現(xiàn)的.
private StringBuffer buf;
//創(chuàng)建默認(rèn)緩沖為16個(gè)字符的StringWriter.默認(rèn)的StringBuffer實(shí)際是大小為16個(gè)字符的字符數(shù)組.
public StringWriter() {
buf = new StringBuffer();
lock = buf;
}
//創(chuàng)建指定大小StringBuffer的StringWriter,也就是指定了initialSize個(gè)字符的字符數(shù)組.
public StringWriter(int initialSize) {
if (initialSize < 0) {
throw new IllegalArgumentException("Negative buffer size");
}
buf = new StringBuffer(initialSize);
lock = buf;
}
//向流寫入單個(gè)字符c
public void write(int c) {
buf.append((char) c);
}
//將字符數(shù)組cbuf中off位置開始,len個(gè)字符寫到流中
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);
}
//將字符串str寫到流中
public void write(String str) {
buf.append(str);
}
//將字符串str中off位置開始,len個(gè)字符寫到流中
public void write(String str, int off, int len) {
buf.append(str.substring(off, off + len));
}
//將字符序列csq添加到流中.
public StringWriter append(CharSequence csq) {
if (csq == null)
write("null");
else
write(csq.toString());
return this;
}
//將字符序列csq中start位置到end之間的字符添加到流中
public StringWriter append(CharSequence csq, int start, int end) {
CharSequence cs = (csq == null ? "null" : csq);
write(cs.subSequence(start, end).toString());
return this;
}
//向流中添加一個(gè)字符c
public StringWriter append(char c) {
write(c);
return this;
}
//將流中字符轉(zhuǎn)換成字符串返回.
public String toString() {
return buf.toString();
}
//返回流的內(nèi)容,即StringBuffer
public StringBuffer getBuffer() {
return buf;
}
//刷新流,沒有具體實(shí)現(xiàn).
public void flush() {
}
//關(guān)閉流后讀取數(shù)據(jù)不會拋出異常,因?yàn)闆]有具體實(shí)現(xiàn)
public void close() throws IOException {
}
}
2,StringReader源碼分析
public class StringReader extends Reader {
//流中實(shí)際數(shù)據(jù)就是通過構(gòu)造方法傳入str字符串.
private String str;
//字符串str的長度
private int length;
//下一個(gè)要讀取字符的位置.
private int next = 0;
//標(biāo)記的位置.
private int mark = 0;
//創(chuàng)建一個(gè)StringReader流,參數(shù)傳入的是字符串s
public StringReader(String s) {
this.str = s;
this.length = s.length();
}
//確保流沒有關(guān)閉,實(shí)際判斷的是StringReader構(gòu)造方法是否有傳入字符串.
private void ensureOpen() throws IOException {
if (str == null)
throw new IOException("Stream closed");
}
//讀取單個(gè)字符
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
if (next >= length)
return -1;
return str.charAt(next++);
}
}
//將緩沖區(qū)中最多l(xiāng)en個(gè)字符寫到字符數(shù)組cbuf中,位置從off開始,長度為len個(gè)
public int read(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {
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;
}
//超過字符串的長度,返回-1
if (next >= length)
return -1;
//剩余可讀取的字符為length-next,
//如果len超過剩余可讀取字符,實(shí)際只能讀取剩余可讀取字符
//如果len小于剩余可讀取字符,實(shí)際上讀取的是len個(gè)字符
int n = Math.min(length - next, len);
str.getChars(next, next + n, cbuf, off);
next += n;
return n;
}
}
//跳過ns個(gè)字符,返回跳過的字符數(shù)
public long skip(long ns) throws IOException {
synchronized (lock) {
ensureOpen();
if (next >= length)
return 0;
// Bound skip by beginning and end of the source
//緩沖區(qū)中剩余字符數(shù)與要跳過的字符數(shù)比較.取較小值
long n = Math.min(length - next, ns);
n = Math.max(-next, n);
next += n;
return n;
}
}
//流是否準(zhǔn)備讀取.
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return true;
}
}
//流是否支持標(biāo)記
public boolean markSupported() {
return true;
}
//標(biāo)記緩沖區(qū)中當(dāng)前位置,readAheadLimit表示的是在保留標(biāo)記的情況下,最大可讀取的字符數(shù)
public void mark(int readAheadLimit) throws IOException {
if (readAheadLimit < 0){
throw new IllegalArgumentException("Read-ahead limit < 0");
}
synchronized (lock) {
ensureOpen();
mark = next;
}
}
//將緩沖區(qū)當(dāng)前位置重置到標(biāo)記位置
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
next = mark;
}
}
//關(guān)閉流,釋放相關(guān)資源(實(shí)際只是將流中內(nèi)容字符串置為空)
public void close() {
str = null;
}
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java高級之虛擬機(jī)加載機(jī)制的實(shí)例講解
下面小編就為大家分享一篇Java高級之虛擬機(jī)加載機(jī)制的實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
Java通過反射機(jī)制將對象封裝成JSON和JsonArray格式
這篇文章主要介紹了Java通過反射機(jī)制將對象封裝成JSON和JsonArray格式,JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個(gè)實(shí)體類,都能夠知道這個(gè)類的所有屬性和方法,需要的朋友可以參考下2023-10-10
總結(jié)Java常用加解密方法AES?SHA1?md5
這篇文章主要為大家介紹了Java常用加密方法AES?SHA1?md5總結(jié)及示例demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
SpringMVC @RequestBody Date類型的Json轉(zhuǎn)換方式
這篇文章主要介紹了SpringMVC @RequestBody Date類型的Json轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Java實(shí)現(xiàn)產(chǎn)生隨機(jī)字符串主鍵的UUID工具類
這篇文章主要介紹了Java實(shí)現(xiàn)產(chǎn)生隨機(jī)字符串主鍵的UUID工具類,涉及java隨機(jī)數(shù)與字符串遍歷、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
淺談@RequestBody和@RequestParam可以同時(shí)使用
這篇文章主要介紹了@RequestBody和@RequestParam可以同時(shí)使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringMVC中@Valid不起效BindingResult讀取不到Error信息
在寫SpringMVC項(xiàng)目時(shí),由于要對表單數(shù)據(jù)進(jìn)行校驗(yàn),需要使用@Valid進(jìn)行校驗(yàn),但是在進(jìn)行數(shù)據(jù)校驗(yàn)時(shí),BindingResult對象無法攔截非法表單數(shù)據(jù),result.hasErrors()無論怎么輸入都會返回false,本文詳細(xì)的介紹一下解決方法2021-09-09
從零開始搭建springboot+springcloud+mybatis本地項(xiàng)目全過程(圖解)
這篇文章主要介紹了從零開始搭建springboot+springcloud+mybatis本地項(xiàng)目全過程(圖解),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
劍指Offer之Java算法習(xí)題精講鏈表與二叉樹專項(xiàng)訓(xùn)練
跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化2022-03-03

