輸入流

在Java中,能夠讀取一個位元組序列的對象就稱作一個輸入流。

概述

在Java中,我們把能夠讀取一個位元組序列的對象稱作一個輸入流;而我們把夠寫一個位元組序列稱作一個輸出流。它們分別由抽象類InputStream和OutputStream類表示。

java的輸入流

當然,我們經常想做的一件事情是將格式化的輸出列印到控制台,但那已在第5章創建的com.bruceeckel.tools中得到了簡化。
第1到第4部分演示了輸入流的創建與使用(儘管第4部分展示了將輸出流作為一個測試工具的簡單套用)。
1.緩衝的輸入檔案
為打開一個檔案以便輸入,需要使用一個FileInputStream,同時將一個String或File對象作為檔案名稱使用。為提高速度,最好先對檔案進行緩衝處理,從而獲得用於一個BufferedInputStream的構建器的結果句柄。為了以格式化的形式讀取輸入數據,我們將那個結果句柄賦給用於一個DataInputStream的構建器。DataInputStream是我們的最終(final)對象,並是我們進行讀取操作的接口。
在這個例子中,只用到了ReadLine()方法,但理所當然任何DataInputStream方法都可以採用。一旦抵達檔案末尾,readLine()就會返回一個null(空),以便中止並退出while循環。
“Strings2”用於聚集完整的檔案內容(包括必須添加的新行,因為readLine()去除了那些行)。隨後,在本程式的後面部分中使用s2。最後,我們調用close(),用它關閉檔案。從技術上說,會在運行finalize()時調用close()。而且我們希望一旦程式退出,就發生這種情況(無論是否進行垃圾收集)。然而,Java1.0有一個非常突出的錯誤(Bug),造成這種情況不會發生。在Java1.1中,必須明確調用System.runFinalizersOnExit(true),用它保證會為系統中的每個對象調用finalize()。然而,最安全的方法還是為檔案明確調用close()。
2.從記憶體輸入
這一部分採用已經包含了完整檔案內容的Strings2,並用它創建一個StringBufferInputStream(字串緩衝輸入流)——作為構建器的參數,要求使用一個String,而非一個StringBuffer)。隨後,我們用read()依次讀取每個字元,並將其傳送至控制台。注意read()將下一個位元組返回為int,所以必須將其造型為一個char,以便正確地列印。
3.格式化記憶體輸入
StringBufferInputStream的接口是有限的,所以通常需要將其封裝到一個DataInputStream內,從而增強它的能力。然而,若選擇用readByte()每次讀出一個字元,那么所有值都是有效的,所以不可再用返回值來偵測何時結束輸入。相反,可用available()方法判斷有多少字元可用。下面這個例子展示了如何從檔案中一次讀出一個字元:
//:TestEOF.java
//Testingfortheendoffilewhilereading
//abyteatatime.
importjava.io.*;
publicclassTestEOF{
publicstaticvoidmain(String[]args){
try{
DataInputStreamin=
newDataInputStream(
newBufferedInputStream(
newFileInputStream("TestEof.java")));
while(in.available()!=0)
System.out.print((char)in.readByte());
}catch(IOExceptione){
System.err.println("IOException");
}
}
}///:~注意取決於當前從什麼媒體讀入,avaiable()的工作方式也是有所區別的。它在字面上意味著“可以不受阻塞讀取的位元組數量”。對一個檔案來說,它意味著整個檔案。但對一個不同種類的數據流來說,它卻可能有不同的含義。因此在使用時應考慮周全。
為了在這樣的情況下偵測輸入的結束,也可以通過捕獲一個違例來實現。然而,若真的用違例來控制數據流,卻顯得有些大材小用。
4.行的編號與檔案輸出
這個例子展示了如何LineNumberInputStream來跟蹤輸入行的編號。在這裡,不可簡單地將所有構建器都組合起來,因為必須保持LineNumberInputStream的一個句柄(注意這並非一種繼承環境,所以不能簡單地將in4造型到一個LineNumberInputStream)。因此,li容納了指向LineNumberInputStream的句柄,然後在它的基礎上創建一個DataInputStream,以便讀入數據。
這個例子也展示了如何將格式化數據寫入一個檔案。首先創建了一個FileOutputStream,用它同一個檔案連線。考慮到效率方面的原因,它生成了一個BufferedOutputStream。這幾乎肯定是我們一般的做法,但卻必須明確地這樣做。隨後為了進行格式化,它轉換成一個PrintStream。用這種方式創建的數據檔案可作為一個原始的文本檔案讀取。
標誌DataInputStream何時結束的一個方法是readLine()。一旦沒有更多的字串可以讀取,它就會返回null。每個行都會伴隨自己的行號列印到檔案里。該行號可通過li查詢。
可看到用於out1的、一個明確指定的close()。若程式準備掉轉頭來,並再次讀取相同的檔案,這種做法就顯得相當有用。然而,該程式直到結束也沒有檢查檔案IODemo.txt。正如以前指出的那樣,如果不為自己的所有輸出檔案調用close(),就可能發現緩衝區不會得到刷新,造成它們不完整。

清空C++標準輸入流緩衝區

調用iostream輸入數據時,若用戶輸入的數據類型與要求的不符(比如要求讀入整數而用戶輸入的不是數字),則cin會被設定為fail(可以用!cin判斷),而用戶輸入的數據仍然留在流緩衝區里,需要手動清空:
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');

相關詞條

相關搜尋

熱門詞條

聯絡我們