流類
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!!!",可以自己嘗試一下。