| 類型 | 定義 | 特徵 | 典型代表 |
|---|---|---|---|
| 節點流 | 直接連接資料源/目的地(檔案、記憶體、網路) | 資料的實際讀寫者 | FileInputStream, ByteArrayInputStream |
| 處理流 | 包裝現有流,提供額外功能(緩衝、轉換、序列化) | 建構子需傳入另一個流,形成流鏈 | BufferedReader, InputStreamReader |
關鍵原則:關閉處理流會自動關閉被包裝的節點流;流可多層包裝形成鏈(如 new BufferedReader(new InputStreamReader(new FileInputStream(file))))。
| 分類 | 位元組流 (InputStream/OutputStream) | 字元流 (Reader/Writer) | 資料源 |
|---|---|---|---|
| 檔案 | FileInputStream / FileOutputStream | FileReader / FileWriter | 磁碟檔案 |
| 陣列 | ByteArrayInputStream / ByteArrayOutputStream | CharArrayReader / CharArrayWriter | 記憶體陣列 |
| 字串 | 無 | StringReader / StringWriter | 字串緩衝區 |
| 管道 | PipedInputStream / PipedOutputStream | PipedReader / PipedWriter | 執行緒間通訊 |
// 位元組緩衝
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("in.dat"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("out.dat"));
// 字元緩衝(支援 readLine())
BufferedReader br = new BufferedReader(new FileReader("text.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
核心優勢:減少系統呼叫次數,預設 8KB 緩衝區可調整。注意:寫入端需手動 flush() 強制輸出。
// 位元組 → 字元(指定編碼,避免平台預設編碼差異)
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"), "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out.txt"), "UTF-8");
解決 FileReader/FileWriter 硬編碼平台預設編碼的痛點。
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"));
dos.writeLong(12345L); // 固定 8 位元組
dos.writeInt(100); // 固定 4 位元組
dos.writeUTF("中文"); // UTF-8 編碼 + 長度前綴
DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"));
long v1 = dis.readLong(); // 必須與寫入順序、型別完全一致
int v2 = dis.readInt();
String v3 = dis.readUTF();
優勢:比「轉字串再轉位元組」節省空間、速度更快。風險:讀取順序/型別不匹配會導致資料錯位。
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.dat"));
oos.writeObject(userList); // 需實作 Serializable
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.dat"));
List list = (List) ois.readObject();
| 關鍵字/介面 | 作用 |
|---|---|
transient | 標記欄位不序列化(如密碼、暫存欄位) |
Serializable | 標記介面,JVM 檢查 instanceof Serializable |
serialVersionUID | 版本控制,避免類變更導致反序列化失敗 |
Externalizable | 手動控制序列化細節(writeExternal/readExternal) |
PrintStream ps = new PrintStream(new FileOutputStream("log.txt"));
System.setOut(ps); // 重導向標準輸出
System.out.println("此行寫入檔案,不拋 IOException");
JSP/Servlet 大量使用 PrintWriter(response.getWriter()),設計初衷:Web 輸出不應因 IO 異常中斷請求處理。
根因:Java 內部用 UTF-16 (char 2 位元組),中文佔 2 位元組。位元組流單讀 1 位元組會截斷字元。
解決:堅持使用字元流 (Reader/Writer) 處理文本,或指定編碼的轉換流。
try (BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream("data.txt"), "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
process(line);
}
} // 自動關閉,無需 finally
public void copyLargeFile(File src, File dest) throws IOException {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
FileChannel in = fis.getChannel();
FileChannel out = fos.getChannel()) {
// NIO 零拷貝,效能最優
in.transferTo(0, in.size(), out);
}
}
Java IO 設計精妙地運用裝飾者模式:節點流負責「連接」,處理流負責「增強」。掌握「位元組流處理二進位、字元流處理文本、轉換流橋接兩者、緩衝流提升效能、物件流實現持久化」五大核心場景,即可駕馭絕大多數 IO 需求。現代專案更推薦 NIO.2 (Files, Path, FileChannel) 簡化程式碼並發揮零拷貝優勢。