複製鏈接
請複製以下鏈接發送給好友

輸入流

鎖定
在Java中,能夠讀取一個字節序列的對象就稱作一個輸入流。
中文名
輸入流
外文名
Input Stream
領    域
Java
表    示
InputStream和OutputStream
含    義
讀取一個字節序列的對象

輸入流定義

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

輸入流教材截取

當然,我們經常想做的一件事情是將格式化的輸出打印到控制枱,但那已在第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(),就可能發現緩衝區不會得到刷新,造成它們不完整。

輸入流緩衝區

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