在java.io包中還有許多其他的流,主要是為了提高效能和使用方便。C/C++只能提供位元組流。Java中的流分為兩種,一種是位元組流,另一種是字元流,分別由四個抽象類別來表示(每種流包括輸入和輸出兩種所以一共四個):InputStream,OutputStream,Reader,Writer。Java中其他多種多樣變化的流均是由它們派生出來的.
字元流和位元組流是根據處理資料的不同來區分的。位元組流按照8位傳輸,位元組流是最基本的,所有檔案的儲存是都是位元組(byte)的儲存,在磁碟上保留的並不是檔案的字元而是先把字元編碼成位元組,再儲存這些位元組到磁碟。
1.位元組流可用於任何類型的對象,包括二進位對象,而字元流只能處理字元或者字串;
2. 位元組流提供了處理任何類型的IO操作的功能,但它不能直接處理Unicode字元,而字元流就可以。
讀文本的時候用字元流,例如txt檔案。讀非文字檔的時候用位元組流,例如mp3。理論上任何檔案都能夠用位元組流讀取,但當讀取的是文本資料時,為了能還原成文本你必須再經過一個轉換的工序,相對來說字元流就省了這個麻煩,可以有方法直接讀取。
字元流處理的單元為2個位元組的Unicode字元,分別操作字元、字元數組或字串,而位元組流處理單元為1個位元組, 操作位元組和位元組數組。所以字元流是由Java虛擬機器將位元組轉化為2個位元組的Unicode字元為單位的字元而成的,所以它對多國語言支援性比較好。
1.位元組流:繼承於InputStream / OutputStream。
OutputStream提供的方法:
void write(int b):寫入一個位元組的資料
void write(byte[] buffer):將數組buffer的資料寫入流
void write(byte[] buffer,int offset,int len):從buffer[offset]開始,寫入len個位元組的資料
void flush():強制將buffer內的資料寫入流
void close():關閉流
InputStream提供的方法:
int read():讀出一個位元組的資料,如果已達檔案的末端,傳回值為-1
int read(byte[] buffer):讀出buffer大小的資料,傳回值為實際所讀出的位元組數
int read(byte[] buffer,int offset,int len)
int available():返迴流內可供讀取的位元組數目
long skip(long n):跳過n個位元組的資料,傳回值為實際所跳過的資料數
void close():關閉流
2.字元流,繼承於InputStreamReader / OutputStreamWriter。
字元流的類:1),BufferedReader是一種過濾器(filter)(extends FilterReader)。過濾
器用來將流的資料加以處理再輸出。建構函式為:
BufferedReader(Reader in):產生一個緩衝的字元輸入資料流,in為一個讀取器
BufferedReader(Reader in,int size):產生一個緩衝的字元輸入資料流,並指定緩衝區的大小為size
public class IOStreamDemo { public void samples() throws IOException { //1. 這是從鍵盤讀入一行資料,返回的是一個字串 BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in)); System.out.print("Enter a line:"); System.out.println(stdin.readLine()); //2. 這是從檔案中逐行讀入資料 BufferedReader in = new BufferedReader(new FileReader("IOStreamDemo.java")); String s, s2 = new String(); while((s = in.readLine())!= null) s2 += s + "/n"; in.close(); //3. 這是從一個字串中逐個讀入位元組 StringReader in1 = new StringReader(s2); int c; while((c = in1.read()) != -1) System.out.print((char)c); //4. 這是將一個字串寫入檔案 try { BufferedReader in2 = new BufferedReader(new StringReader(s2)); PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out"))); int lineCount = 1; while((s = in2.readLine()) != null ) out1.println(lineCount++ + ": " + s); out1.close(); } catch(EOFException e) { System.err.println("End of stream"); } } }
對於上面的例子,需要說明的有以下幾點:
1. InputStreamReader是InputStream和Reader之間的橋樑,由於System.in是位元組流,需要用它來封裝之後變為字元流供給BufferedReader使用。
3. PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
這句話體現了Java輸入輸出系統的一個特點,為了達到某個目的,需要封裝好幾層。首先,輸出目的地是檔案IODemo.out,所以最內層封裝的是FileWriter,建立一個輸出檔案流,接下來,我們希望這個流是緩衝的,所以用BufferedWriter來封裝它以達到目的,最後,我們需要格式化輸出結果,於是將PrintWriter包在最外層。
Java流有著另一個重要的用途,那就是利用物件流程對對象進行序列化。
在一個程式啟動並執行時候,其中的變數資料是儲存在記憶體中的,一旦程式結束這些資料將不會被儲存,一種解決的辦法是將資料寫入檔案,而Java中提供了一種機制,它可以將程式中的對象寫入檔案,之後再從檔案中把對象讀出來重建立立。這就是所謂的對象序列化。Java中引入它主要是為了RMI(Remote Method Invocation)和Java Bean所用,不過在平時應用中,它也是很有用的一種技術。