java流與介面卡模式
JavaI/O最關鍵的4個類是InputStream(輸入位元組流)、OutputStream(輸出位元組流)、Reader(輸入字元流)、Writer(輸出字元流),它們都是publicabstractclass類。
InputSream和OutputStream對於資料的傳送是以位元組Byte為單位的,而Reader和Writer對於資料的傳送是以字元Character為單位的。所以我們看到java.io包中的類大體上可以分為兩大類,一類是以Byte處理為主的Stream類,它們都是以XXXStream方式命名的;一類是以Character處理為主的Reader/Writer類,它們都是以XXXReader或XXXWriter的方式命名的。
表12-1展示了InputStream、OutputStream、Reader、Writer的各種實現的子類。可以分為3類:資料來源類、資料流串聯類、資料流過濾類。其中的資料來源類是建立各種流的起始類,第二類和第三類都是對各自流例項的包裝。
表12-1輸入/輸出流類列表
然而,位元組流與字元流之間的區別卻可以聯絡起來,這就是表中的兩個類InputStreamReader和OutputStreamReader。InputStreamReader負責把位元組輸入流轉換為字元輸入流,OutputStreamReader負責把輸出位元組流轉換為輸出字元流。下面來看看如何進行轉換。關於該表中各種類及其原理的使用,詳細參見《Java高手真經-Java核心程式設計技術》一書。
從上表可以看出,以字元為導向的reader/writer基本上有與之相對應的以位元組為導向的stream。兩個對應類實現的功能相同,只是在操作時的導向不同。如CharArrayReader和ByteArrayInputStream的作用都是把記憶體中的一個緩衝區作為流使用,所不同的是前者每次從記憶體中讀取一個位元組的資訊,而後者每次從記憶體中讀取一個字元。
1.位元組輸入流轉換為字元輸入流
InputStreamReader是位元組流通向字元流的橋樑,它使用指定的charset讀取位元組並將其解碼為字元。它擁有一個InputStream型別的變數,並繼承了Reader,使用了物件的介面卡模式,如圖12-9所示。
根據InputStream的例項建立InputStreamReader的方法有4種:
InputStreamReader(InputStreamin);
//根據預設字符集建立
InputStreamReader(InputStreamin,Charsetcs);
//使用給定字符集建立
InputStreamReader(InputStreamin,CharsetDecoderdec);
//使用給定字符集解碼器建立
InputStreamReader(InputStreamin,StringcharsetName);
//使用指定字符集建立
後面的3個建構函式都指定了一個字符集,最後一個是最簡單的,可以直接指定字符集的名稱來建立,例如GB2312等。
每次呼叫InputStreamReader中的一個read()方法都會導致從底層輸入流讀取一個或多個位元組。要啟用從位元組到字元的有效轉換,可以提前從底層流讀取更多的位元組,使其超過滿足當前讀取操作所需的位元組。共有3個可用的read()方法:
intread();
//讀取單個字元
intread(char[]cbuf,intoffset,intlength);
//將字元讀入陣列中的某一部分
booleanready();
//判斷此流是否已經準備好用於讀取
InputStreamReader繼承自Reader,因此該類的例項可以被各種輸入字元流包裝。為了達到最高效率,可以考慮在BufferedReader內包裝InputStreamReader。例如程式12-20所示,我們首先建立了一個FileInputStream類的例項,然後轉換為InputStreamReader物件is,最後使用BufferedReader進行包裝。這樣就可以將位元組流轉換為帶緩衝功能的字元流。
程式12-20TestInputStreamReader.java
publicclassTestInputStreamReader{
publicstaticvoidmain(String[]args){
try{
//建立輸入流
FileInputStreamfis=newFileInputStream("D:/demo/test.txt");
InputStreamReaderis=newInputStreamReader(fis);
BufferedReaderbis=newBufferedReader(is);
//從輸入流讀取資料
while(bis.ready()){
intc=bis.read();
System.out.print((char)c);
}
//關閉輸入流
bis.close();
is.close();
fis.close();
}catch(IOExceptione){
}
}
}
2.位元組輸出流轉換為字元輸出流
OutputStreamWriter是字元流通向位元組流的橋樑,可使用指定的charset將要寫入流中的字元編碼成位元組。因此,它擁有一個OutputStream型別的變數,並繼承了Writer,使用了物件的介面卡模式,如圖12-10所示。
根據OutputStream的例項建立OutputStreamWriter的方法有4種:
OutputStreamReader(OutputStreamout);
//根據預設字符集建立
OutputStreamReader(OutputStreamout,Charsetcs);
//使用給定字符集建立
OutputStreamReader(OutputStreamout,CharsetDecoderdec);
//使用給定字符集解碼器建立
OutputStreamReader(OutputStreamout,StroutgcharsetName);
//使用指定字符集建立
後面的3個建構函式都制定了一個字符集,最後一個是最簡單的,可以直接指定字符集的名稱來建立,例如GB2312等。
每次呼叫write()方法都會導致在給定字元(或字符集)上呼叫編碼轉換器。在寫入底層輸出流之前,得到的這些位元組將在緩衝區中累積。可以指定此緩衝區的大小,不過,預設的緩衝區對多數用途來說已足夠大。注意,傳遞給write()方法的字元沒有緩衝。共有3個可用的write()方法:
voidwrite(char[]cbuf,intoff,intlen);//寫入字元陣列的某一部分
voidwrite(intc);//寫入單個字元
voidwrite(Stringstr,intoff,intlen);//寫入字串的某一部分
OutputStreamWriter繼承自Writer,因此該類的例項可以被各種輸出字元流包裝。為了達到最高效率,可以考慮在BufferedWriter內包裝OutputStreamWriter。例如程式12-21所示,我們首先建立了一個FileOutputStream類的例項,然後轉換為OutputStreamReader物件os,最後使用BufferedWriter進行包裝。這樣就可以將位元組流轉換為帶緩衝功能的字元流。
程式12-21TestOutputStreamWriter.java
publicclassTestOutputStreamWriter{
publicstaticvoidmain(String[]args){
try{
//建立輸出流
FileOutputStreamfos=newFileOutputStream("D:/demo/test.txt");
OutputStreamWriteros=newOutputStreamWriter(fos);
BufferedWriterbos=newBufferedWriter(os);
//寫入陣列資料
char[]buf=newchar[3];
buf[0]='a';
buf[1]='b';
buf[2]='中';
bos.write(buf);
//關閉輸出流
bos.close();
os.close();
fos.close();
}catch(IOExceptione){
}
}
}
轉載於:https://my.oschina.net/91jason/blog/309824