1. 程式人生 > >Java -- 流與檔案01

Java -- 流與檔案01

Java中用於輸入和輸出的各種應用程式設計介面(Application Programming Interface, API)。在Java API中,可以在其中讀入一個位元組序列的物件稱做輸入流,而可以向其中寫入一個位元組序列的物件稱做輸出流。這些位元組序列的來源地和目的地可以是檔案,而且通常是檔案,但是也可以是網路連線,甚至是記憶體塊。
抽象類InputStream和OutputStream構成了輸入/輸出(I/O)類層次結構的基礎。因為面向位元組的流不便於處理以Unicode形式儲存的資訊,Unicode中每個字元都使用了多個位元組來表示,所以從抽象類Reader和Writer中繼承出來了一個專門用於處理Unicode字元的單獨的類層次結構。這些類都是基於兩位元組的Unicode碼元,而不是基於單位元組的字元。

讀寫位元組

InputStream類有一個抽象方法:abstract int read(),這個方法將讀入一個位元組,並返回讀入的位元組,或者在遇到輸入源結尾是返回-1.在設計具體的輸入流類時,必須覆蓋這個方法以提供使用的功能。InputStream類還有若干個非抽象的方法,它們可以讀入一個位元組陣列,或者跳過大量的位元組。這些方法都要呼叫抽象的read方法,因此每個子類都只需覆蓋這一個方法。
OutputStream類定義了下面的抽象方法,abstract void write(int b),它可以向某個輸出位置寫出一個位元組。
read和write方法在執行時都將阻塞,直至位元組確實被讀入或寫出。 available方法檢查當前可讀入的位元組數量。但完成了對流的讀寫,應該呼叫close方法來關閉它,這個呼叫會釋放掉有限的作業系統資源,如果一個應用程式打開了過多的流而沒有關閉,那麼系統資源將被耗盡。關閉一個輸入流同時會沖刷用於該輸出流的緩衝區。Java提供了眾多從基本的InputStream和OutputStream類匯出的類,這些類使我們可以處理那些以常用格式表示的資料,而不是位元組。

完整的流家族

Java擁有一個流家族,包含各種流型別,其數量超過60個。按照它們的使用方法來進行劃分,這樣就形成了處理位元組和字元的兩個單獨的層次結構。DataInputStream和DataOutputStream可以以二進位制格式讀寫所有的基本Java型別。

組合流過濾器

FileInputStream和FileOutputStream可以提供附著在一個磁碟檔案上的輸入流和輸出流,而你只需向其構造器提供檔名或檔案的完整路徑名。所有的java.io中的類都將相對路徑解釋為以使用者工作目錄開始。可以通過呼叫System.getProperty("user.dir")來獲得這個資訊。windows系統下,可以使用單斜槓字元,由於反斜槓字元在Java中是轉義字元,所以要用雙反斜槓。而對於可移植的程式來說,應該使用程式所執行平臺的檔案分隔符,我們可以通過常量字串java.io.File.separator來獲得它。
Java提供了一種靈巧的機制。某些流(例如FileInputStream和由URL類的openStream方法返回的輸入流)可以從檔案和其他更外部的位置上獲得位元組。而其他的流(例如DataInputStream和PrintWriter)可以將位元組組裝到更有用的資料型別。如:
/*從檔案中讀入數字*/
FileInputStream fin = new FileInputStream("employee.dat");
DataInputStream din = new DataInputStream(fin);
double s = din.readDouble();

可以通過巢狀過濾器來新增多重功能,例如,流在預設情況下是不被緩衝池快取的,即每個對read的呼叫都會請求作業系統再分發一個位元組。使用緩衝機制顯得更高效,如用於檔案的資料輸入方法:
DataInputStream din = new DataInputStream(
	new BufferedInputStream(
		new FileInputStream("employee.dat")));

有時當多個流連結在一起時,需要跟蹤各個中介流。 如:當讀入輸入時,需要瀏覽下一個位元組,以瞭解它是否是想要的值。Java提供了PushbackInputStream:
PushbackInputStream pbin = new PushbackInputStream(
	new BufferedInputStream(
		new FileInputStream("employee.dat")));

/*預讀下一個位元組*/
int b = pbin.read();

/*在它並非你所期望的值時將其推回流中*/
if(b != '<')	pbin.unread(b);

/*讀入和回推是可回推輸入流的僅有方法,如想預先瀏覽並且可以讀入數字,那麼就需要一個
既是可回推輸入流,又是一個數據輸入流的引用*/
DataInputStream din = new DataInputStream(
	pbin = new PushbackInputStream(
		new BufferedInputStream(
			new FileInputStream("employee.dat"))));

文字輸入與輸出

在儲存資料時,可以選擇二進位制格式或文字格式。OutputStreamWriter類將使用選定的字元編碼方式,把Unicode字元流轉換為位元組流。而InputStreamReader類將包含位元組(用某種字元編碼方式表示的字元)的輸入流轉換為可以產生Unicode碼元的讀入器。 如讓一個輸入讀入器可以從控制檯讀入鍵盤敲擊資訊: InputStreamReader in = new InputStreamReader(System.in);

如何寫出文字輸出

對於文字輸出,可以使用PrintWriter。這個類擁有以文字格式列印字串和數字的方法,甚至有一個將PrintWriter連結到FileWriter的便捷方法。 PrintWriter out = new PrintWriter("employee.txt"); 等價於 PrintWriter out = new PrintWriter(new FileWriter("employee.txt"));
為了輸入到列印寫出器,需要使用與使用System.out相同的print, println和printf方法。
String name = "Harry Hacker";
double salary = 75000;
out.print(name);
out.print(' ');
out.println(salary);
/*將Harry Hacker 75000.0 輸入到 寫入器 out中。之後這些字元被轉換為位元組並最終寫入employee.txt中*/
如果寫出器設定為自動沖刷模式,那麼只要println被呼叫,緩衝區中的所有字元都會被髮送到它們的目的地。預設情況下,自動沖刷機制是禁用的。可以通過呼叫PrintWriter(Writer out, Boolean autoFlush)來啟用或禁用自動沖刷機制。

如何讀入文字輸入

在Java5.0之前,處理文字輸入的唯一方式是通過BufferedReader類,它擁有一個readLine方法,使得可以讀入一行字元。
BufferedReader in = new BufferedReader(
	new InputStreamReader(new FileInputStream("employee.txt"), "UTF-8"));
然而,BufferedReader沒有任何用於讀入數字的方法,所以我們使用Scanner來讀入文字輸入。