java.io 核心抽象是 Stream (流):有序位元組/字符序列的來源 (Input) 或目的地 (Output)。所有資料經序列化寫入輸出流、或從輸入流讀取。設計核心採用 裝飾者模式:基礎流 (節點流) 對接物理設備 (檔案、記憶體、網路),處理流 (包裝流) 疊加功能 (緩衝、格式化、物件序列化、編碼轉換),靈活組合、動態擴展。
| 方向 | 基礎節點流 | 功能 | 核心處理流 (裝飾者) | 功能 |
|---|---|---|---|---|
| Input | FileInputStream | 讀取檔案 | BufferedInputStream | 緩衝讀取,大幅提升效能 |
ByteArrayInputStream | 讀取記憶體 byte[] | DataInputStream | 讀取基本類型 (int, double 等) | |
PipedInputStream | 執行緒間管道輸入 | ObjectInputStream | 反序列化物件 (配合 Serializable) | |
SequenceInputStream | 合併多個輸入流 | PushbackInputStream | 回推位元組 (編譯器/解析器用) | |
StringBufferInputStream (已棄用) | 讀取 StringBuffer | - | - | |
| Output | FileOutputStream | 寫入檔案 | BufferedOutputStream | 緩衝寫入,批次刷新 |
ByteArrayOutputStream | 寫入記憶體 byte[] | DataOutputStream | 寫入基本類型 | |
PipedOutputStream | 執行緒間管道輸出 | ObjectOutputStream | 序列化物件 | |
SequenceOutputStream (JDK 內部) | 合併多個輸出流 | PrintStream | 格式化輸出 (System.out 即此類) |
字符流 = 位元組流 + InputStreamReader/OutputStreamWriter (編碼轉換橋樑)。
| 方向 | 基礎節點流 | 對應位元組流 | 核心處理流 | 功能 |
|---|---|---|---|---|
| Reader | FileReader | FileInputStream | BufferedReader | 緩衝逐行讀取 (readLine()) |
StringReader | StringBufferInputStream | LineNumberReader | 追蹤行號 | |
CharArrayReader | ByteArrayInputStream | PushbackReader | 回推字符 | |
PipedReader | PipedInputStream | - | - | |
| Writer | FileWriter | FileOutputStream | BufferedWriter | 緩衝寫入、newLine() 跨平台換行 |
StringWriter | 無直接對應 | PrintWriter | 格式化輸出 (含 println/printf)、不拋異常 | |
CharArrayWriter | ByteArrayOutputStream | - | - | |
PipedWriter | PipedOutputStream | - | - |
InputStreamReader(InputStream in, Charset charset):位元組流 → 字符流 (指定編碼,**生產必須顯式指定編碼**)。OutputStreamWriter(OutputStream out, Charset charset):字符流 → 位元組流。DataInput/DataOutput,支援 seek(long pos) 任意位置讀寫。"r" (唯讀)、"rw" (讀寫)、"rws"/"rwd" (同步寫入)。import java.io.*;
public class IODemo {
public static void main(String[] args) throws IOException {
// 1. 緩衝逐行讀取檔案 + 鍵盤輸入
try (BufferedReader in = new BufferedReader(new FileReader("src/IODemo.java"));
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in))) {
String line;
while ((line = in.readLine()) != null) System.out.println(line);
System.out.print("輸入一行: ");
System.out.println("你輸入: " + stdin.readLine());
}
// 2. 從字串讀取 (字符流)
String content = "Hello\nWorld";
try (StringReader sr = new StringReader(content)) {
int c;
while ((c = sr.read()) != -1) System.out.print((char)c);
}
// 3. 記憶體格式化輸入 (位元組流 + DataInput)
try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(content.getBytes()))) {
while (true) System.out.print((char)dis.readByte());
} catch (EOFException ignored) { System.out.println("\n--- 記憶體讀取結束 ---"); }
// 4. 格式化輸出到檔案 (行號 + PrintWriter)
try (BufferedReader br = new BufferedReader(new StringReader(content));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("out.txt")))) {
String l; int i=1;
while ((l = br.readLine()) != null) out.println(i++ + ": " + l);
}
// 5. 基本類型序列化存儲與恢復 (DataOutput/Input + 緩衝)
try (DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.dat")))) {
dos.writeDouble(Math.PI);
dos.writeChars("\nPI via writeChars\n");
dos.writeBytes("PI via writeBytes\n");
}
try (DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("data.dat")));
BufferedReader br = new BufferedReader(new InputStreamReader(dis))) {
System.out.println("Double: " + dis.readDouble());
System.out.println("Chars: " + br.readLine());
System.out.println("Bytes: " + br.readLine());
}
// 6. RandomAccessFile 隨機讀寫
try (RandomAccessFile raf = new RandomAccessFile("random.dat", "rw")) {
for (int i=0; i<10; i++) raf.writeDouble(i * 1.414);
raf.seek(5 * 8); // 定位第 6 個 double
raf.writeDouble(47.0001); // 修改
for (int i=0; i<10; i++) System.out.println("Idx " + i + ": " + raf.readDouble());
}
}
}
new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) — 職責單一、動態擴展、避免繼承爆炸。AutoCloseable,編譯器自動生成 finally 關閉邏輯,**杜絕資源洩漏**。StandardCharsets.UTF_8。ObjectOutputStream 產出二進制強耦合類結構、版本維護困難、安全風險 (反序列化漏洞)。**首選 JSON (Jackson/Gson)、Protobuf、Avro** 進行跨語言/版本數據交換。Files.readAllLines(), Files.walk(), FileChannel 非阻塞 I/O、記憶體映射、檔案屬性/權限/監聽 (WatchService) 功能更強、API 更現代。Java IO 體系雖歷經演進 (IO → NIO → NIO.2),但「流、裝飾者、緩衝、編碼、序列化」核心概念不變。深度理解其架構邏輯,配合現代 API 與最佳實踐,才能寫出高效、健壯、可維護的 I/O 代碼。