當前位置:才華齋>計算機>java語言>

Java中的stream流的解析與應用

java語言 閱讀(2.42W)

流是位元組序列的抽象概念。

Java中的stream流的解析與應用

檔案是資料的靜態儲存形式,而流是指資料傳輸時的形態。

流類分為兩個大類:節點流類和過濾流類(也叫處理流類)。

程式用於直接操作目標裝置所對應的類叫節點流類,程式也可以通過一個間接流類去呼叫節點流類,以達到更加靈活方便地讀取各種型別的資料,這個間接流類就是過濾流類(也叫處理流類),或者稱為包裝類。

包裝類的呼叫過程如下圖:

流分類的關係

不管流的分類是多麼的豐富和複雜,其根源來自於四個基本的類。這個四個類的關係如下:

位元組流 字元流 輸入流 InputStream Reader 輸出流 OutputStream Writer

Java內用 Unicode 編碼儲存字元,字元流處理類負責將外部的其他編碼的字元流和java內 Unicode 字元流之間的轉換。而類InputStreamReader 和OutputStreamWriter處理字元流和位元組流的轉換。字元流(一次可以處理一個緩衝區)一次操作比位元組流(一次一個位元組)效率高。

InputStream

由於InputStream和OutputStream是abstact類,所以它們還不能表明具體對應哪種IO裝置。它們下面有許多子類,包括網路、管道、記憶體、檔案等具體的IO裝置,實際程式中使用的它們的各種子類物件。

注:我們將節點流類所對應的IO源和目標稱為流節點(Node)。

注意:將A檔案的內容寫入B檔案,程式對A檔案的操作所用的是輸出類還是輸入類這個問題。輸入輸出類是相對程式而言的,而不是代表檔案的,所以我們應該建立一個輸入類來完成對A檔案的操作,建立一個輸出類來完成對B檔案的操作。

OutputStream

以字元為導向的 stream Reader/Writer

以 Unicode 字元為導向的 stream ,表示以 Unicode 字元為單位從 stream 中讀取或往 stream 中寫入資訊。同樣,Reader/Writer也為abstact類。

Reader

Writer

IO程式程式碼的複用:

平時寫程式碼用-1來作為鍵盤輸入的結束,在寫的函式中不直接使用,只是在呼叫該函式時,將作為引數傳遞進去,這樣,我們以後要從某個檔案中讀取資料,來代替手工鍵盤輸入時,我們可以直接使用這個函式,程式就不用做太多的修改了,達到以不變應萬變的效果。

位元組流和字元流的'相互轉換

InputStreamReader和OutputStreamReader:把一個以位元組為導向的stream轉換成一個以字元為導向的stream。

InputStreamReader類是從位元組流到字元流的橋樑:它讀入位元組,並根據指定的編碼方式,將之轉換為字元流。

使用的編碼方式可能由名稱指定,或平臺可接受的預設編碼方式。

InputStreamReader的read()方法之一的每次呼叫,可能促使從基本位元組輸入流中讀取一個或多個位元組。

為了達到更高效率,考慮用BufferedReader封裝InputStreamReader,

BufferedReader in = new BufferedReader(new InputStreamReader());

Java流使用的一點總結

最經工作中碰到不少Java流的使用,總結如下:

1. 生成Zip格式,遇到的是要在一個Servlet中生成Zip檔案,輸出到web 客戶端,直接下載。

ontentType("application/zip"); eader("Content-Disposition", "attachment;filename=/"""); ZipOutputStream out = new ZipOutputStream(utputStream()) for() { ZipEntry entry = new ZipEntry("aa" + i ""); ewEntry(entry); bytes[] bt = ytes(); eBytes(bt, 0, th()); eEntry(); } h(); e();

ZipOutputStream 繼承自 erOutputStream. 因此真正的寫操作是通過引數OutputStream out去寫的。

其 void write(byte[] b, int off, int len) 最終呼叫了 e(b, off, len);

如果要生成一個zip檔案,構造時就這樣寫 new ZipOutputStream(new FileOutputStream(path));

2. 類似的寫XML.

XMLWriter writer = new XMLWriter(new FileOutputStream(path), formater)

e(doc).道理和上面類似

3. 寫文字檔案,追加。

PrintStream ps = new PrintStream(new FileOutputStream(path, true), "utf-8")tln(s); // 能寫boolean、int等各種型別。

PrintSteam同樣繼承自FilterOutputStream

其內部使用一個OutputStreamWriter的物件textOut來寫。例如write(String s)最終呼叫到e(s);

這裡涉及到編碼的問題。其引數裡的"utf-8"最終傳遞到OutputStream。

OutputStream是一個字元流和位元組流之間的橋樑。

因此其提供了write(char[] cbuf, int off, int len) 和 write(String str, int off, int len) 用來寫字元和字串。

OutputStream內部又通過一個StreamEncoder物件來序列化字元和字串。

4. 寫出到socket。

DataOutputStream out = new DataOutputStream(utputStream()); eBytes(bt); eBoolean(boolean v) ;

DataOutputStream同樣是一個自FilterOutputStream.

5. 從文字中讀取

BufferedReader reader = new BufferedReader(new FileReader(path)); Line();

BufferedReader的模式和上面的Filter模式一樣,其內部儲存一個Reader物件為引數傳進來並用來實際讀取的物件。

BufferedReader對應java 1.0的類就是BufferedInputStream,是一個FilterInputStream。

6. 從Socket中讀取

BufferedInputStream is = new BufferedInputStream(nputStream()); (bt, 0, th());

總結:

基類Stream系列是InputStream和OutputStream,他們是抽象類,要求的方法只有(以Output為例)

void write(int b) throws IOException;void write(byte b[]) throws IOExceptionvoid write(byte b[], int off, int len)

其最基本的只是位元組操作。第1個方法看似寫一個整數,其實只寫一個位元組(最低八個bit)。其子類分兩個系列,一個是直接操作輸出裝置的,我們上面碰到的有檔案(FileOutputStream)和Servlet輸出(ServletOutputStream)。其他常用的還有一個 ByteArrayOutputStream,是直接在記憶體裡操作的。

再就是FilterOutputStream系列了,都是接收一個OutputStream物件座位引數,真正的寫操作通過該物件去完成。例如ZipOutputStream,其本身只負責生成壓縮格式的資料,至於這些資料是寫到檔案、記憶體、還是servletResponse,由輸入的引數確定。這就是裝飾器模式。

Filter系列常用的有PrintStream(提供了print,println,write(boolean[int, char, string])各種操作,最終利用e方法以寫位元組的方式寫進去。

還有DataOutputStream,其提供了writeByte/writeBoolean/writeDouble/writeLong/wiretUTF等方法。

還有就是socket/zip等不常用的。

Java的流很方便也很複雜。複雜就複雜在實現一個功能往往需要多個類,而且有多種組合的辦法。尚需繼續在實踐中總結。