1. 程式人生 > 實用技巧 >java流與介面卡模式

java流與介面卡模式

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

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輸入/輸出流類列表

215704_lknw_567296.jpg


然而,位元組流與字元流之間的區別卻可以聯絡起來,這就是表中的兩個類InputStreamReader和OutputStreamReader。InputStreamReader負責把位元組輸入流轉換為字元輸入流,OutputStreamReader負責把輸出位元組流轉換為輸出字元流。下面來看看如何進行轉換。
關於該表中各種類及其原理的使用,詳細參見《Java高手真經-Java核心程式設計技術》一書。



從上表可以看出,以字元為導向的reader/writer基本上有與之相對應的以位元組為導向的stream。兩個對應類實現的功能相同,只是在操作時的導向不同。如CharArrayReader和ByteArrayInputStream的作用都是把記憶體中的一個緩衝區作為流使用,所不同的是前者每次從記憶體中讀取一個位元組的資訊,而後者每次從記憶體中讀取一個字元。

1.位元組輸入流轉換為字元輸入流

InputStreamReader是位元組流通向字元流的橋樑,它使用指定的charset讀取位元組並將其解碼為字元。它擁有一個InputStream型別的變數,並繼承了Reader,使用了物件的介面卡模式,如圖12-9所示。

215525_rADh_567296.jpg

根據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所示。

215539_ixmp_567296.jpg

根據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