Java IO3:位元組流

五月的倉頡發表於2015-10-18

流類

Java的流式輸入/輸出是建立在四個抽象類的基礎上的:InputStream、OutputStream、Reader、Writer。它們用來建立具體的流式子類。儘管程式通過具體子類執行輸入/輸出操作,但頂層類定義了所有流類的基本通用功能。

InputStream和OutputStream為位元組流設計,Reader和Writer為字元流設計,位元組流和字元流形成分離的層次結構。一般來說,處理字元或字串使用字元流類,處理位元組或二進位制物件使用位元組流

操作檔案流時,不管是字元流還是位元組流,都可以按照以下方式進行:

1、使用File類找到一個物件

2、通過File類的物件去例項化位元組流或字元流的子類

3、進行位元組(字元)的讀、寫操作

4、關閉檔案流

 

OutputStream(位元組輸出流)

OutputStream是定義了Java流式位元組輸入模式的抽象類。該類的所有方法返回一個void值並且在出錯的情況下引發一個IOException,OutputStream提供的抽象方法有:

方    法 作    用
void close() 關閉輸入流,關閉後的寫操作會引發IOException
flush() 重新整理此輸入流並強制寫出所有緩衝的輸出位元組
write(byte[] b) 向輸入流寫入單個位元組,注意引數是一個int型,它允許設計者不必把引數轉換成位元組型就可以呼叫write()方法
write(byte[] b, int off, int len) 以b[off]為起點,向檔案寫入位元組陣列b中len個位元組
write(int b) 向一個輸出流寫一個完整的位元組陣列

 

FileOutputStream(檔案位元組輸出流)

FileOutpuStream應該是Java中最常見的位元組輸出流了,它建立一個可向檔案寫入位元組的類OutputStream,它常用的構造方法如下:

1、FileOutputStream(String name)

2、FileOutputStream(File file)

3、FileOutputStream(File file, boolean append)

前兩個構造方法類似,前者輸入檔案的絕對路徑,後者輸入File的例項物件,和RandomAccessFile一樣,推薦後者。第三個構造方法有一點不同,append如果設定為true,檔案則以搜尋路徑模式開啟。FileOutputStream的建立不依賴於檔案是否存在,在建立物件時,FileOutputSStream會在開啟輸出檔案之前就建立它。這種情況下如果試圖開啟一個只讀檔案,會引發IOException。FileOutputStream,寫一個例子,現在我的D盤路徑下並沒有"stream.txt"這個檔案:

public static void main(String[] args) throws Exception
{
    File file = new File("D:/stream.txt");
    OutputStream out = new FileOutputStream(file);;
    byte b0[] = "abcdefghijklmnopqrstuvwxyz".getBytes(); //操作位元組流,要轉換成位元組
    out.write(b0);
    out.close();
}

此時開啟"stream.txt":

看到D盤下多了"stream.txt",且檔案中的內容和我們寫入的一致,同樣這個例子也證明了FileOutputStream並不依賴指定路徑下的檔案是否存在。那如果指定路徑下本來就有檔案,那麼寫將會覆蓋而不是追加,很好證明:

public static void main(String[] args) throws Exception
{
    File file = new File("D:/stream.txt");
    OutputStream out = new FileOutputStream(file);;
    byte b0[] = "abcdefghijklmnopqrstuvwxyz".getBytes(); //操作位元組流,要轉換成位元組
    out.write(b0);
    out.close();
}

此時再開啟"stream.txt":

"stream.txt"中的內容變掉了,證明了結論。

 

InputStream(位元組輸入流)

InputStream是定義了Java流式位元組輸入模式的抽象類。該類所有方法在出錯的時候都會引發一個IOException,InputStream提供的抽象方法有:

方    法 作    用
int available() 返回當前可讀的位元組數
void close() 關閉此輸入流並釋放與該流關聯的所有系統資源,關閉之後再讀取會產生IOException
int mark(int readlimit) 在輸入流中放置一個標記,該流在讀取N個Bytes位元組前都保持有效
boolean markSupported() 如果呼叫的流支援mark()/reset()就返回true
int read() 如果下一個位元組可讀取則返回一個整形,遇到檔案尾時返回-1
int read(byte b[]) 試圖讀取buffer.length個位元組到buffer中,並返回實際成功讀取的位元組數,遇到檔案尾則返回-1
int read(byte b[], int off, int len) 將輸入流中最多len個陣列直接讀入byte陣列,off表示陣列b中寫入資料的初始偏移量。注意,三個read方法,在輸入資料可用、檢測到流末尾或者丟擲異常前,此方法將一直阻塞
void reset() 重新設定輸入指標到先前設定的標記處
long skip(long n) 跳過和丟棄此輸入流中資料的n個位元組

 

FileInputStream(檔案位元組輸入流)

FileInputStream應該是Java中最常見的位元組輸入流了,它建立一個能從檔案讀取位元組的InputStream類,它的兩個常用構造方法如下:

1、FileInputStream(String name)

2、FileInputStream(File file)

和FileOutputStream差不多,推薦後者的用法。FileInputStream,同樣寫一個例子,操作的是上面D盤下生成的"stream.txt":

public static void main(String[] args) throws Exception
{
    File file = new File("D:/stream.txt");
    InputStream in = new FileInputStream(file);
byte b1[] = new byte[(int)file.length()]; int i = 0; i = in.read(b1); System.out.println(i); System.out.println(new String(b1, 0, i)); }

執行結果為:

20
Hello World!!!

要區分清楚,OutputStream的作用是將內容由Java記憶體輸出到檔案中、InputStream是將內容由檔案輸入到Java記憶體中。read(byte b[])方法之前講明瞭,表示"試圖讀取buffer.length個位元組到buffer中,並返回實際讀取的位元組數",返回的是實際位元組的大小。不要誤以為"Hello World!!!"是14個字元即28個位元組,位元組流底層是以byte為單位的,因此檔案裡面只有14個位元組罷了,至於返回的是20,還是因為"位元組對齊"的問題。

這裡沒有演示skip方法,因為比較簡單,skip多少無非少讀幾個位元組罷了,skip(3),那麼讀出的就是"lo World!!!",可以自己嘗試一下。

相關文章