Java IO 體系是處理數據輸入輸出的核心基礎,其設計大量運用了裝飾器模式與適配器模式,通過層層包裝賦予基礎流強大功能。本文從底層原理到實戰應用,系統梳理字節流、字符流、緩衝流、過濾流與數據流的協作機制。
Java IO 以四大抽象類為核心,派生出豐富的具體實現:
InputStream / OutputStream —— 處理二進制數據(圖片、視頻、序列化對象)Reader / Writer —— 處理文本數據,內建字符編碼轉換所有具體流類均繼承自這四大基類,並通過構造函數接收另一個同類型流對象,形成鏈式包裝結構。
直接操作 FileInputStream 讀取單個字節時,每次 read() 都觸發系統調用、磁盤尋道、數據傳輸,開銷極大。典型場景下,磁盤 I/O 延遲約 5-10ms,而內存操作僅需 0.1ns —— 差距達 5-10 萬倍。
// 無緩衝:每讀 1 字節 → 1 次系統調用
int b;
while ((b = fis.read()) != -1) { ... }
// 有緩衝:首次讀入 8KB 到內存緩衝區,後續從內存讀取
BufferedInputStream bis = new BufferedInputStream(fis, 8192);
while ((b = bis.read()) != -1) { ... }
flush() 時才一次性刷入磁盤。// 輸入鏈:文件 → 緩衝 → 數據流(可選) → 邏輯處理
DataInputStream dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream("data.bin")));
// 輸出鏈:邏輯處理 → 數據流(可選) → 緩衝 → 文件
DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("data.bin")));
// 輸入:文件 → 字節流 → 編碼轉換 → 緩衝字符流 → 按行讀取
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("log.txt"), "UTF-8"));
// 輸出:邏輯處理 → 自動刷新 PrintWriter → 編碼轉換 → 文件
PrintWriter pw = new PrintWriter(
new OutputStreamWriter(
new FileOutputStream("out.txt"), "UTF-8"), true); // true = autoFlush
read(byte[])、write(byte[])、readLine()、newLine()BufferedOutputStream 必須顯式調用 flush() 確保數據落盤in.read() / out.write(),子類覆寫實現具體邏輯boolean、byte、char、short、int、long、float、double、String (UTF-8 修改版)EOFException 或數據錯位| 陷阱 | 後果 | 解決方案 |
|---|---|---|
| 忘記關閉流 / 關閉順序錯誤 | 資源洩漏、數據丟失、文件鎖定 | 使用 try-with-resources,外層流先關閉(自動關閉內層) |
| 字符流未指定編碼 | 中文亂碼,跨平台不一致 | 強制指定 StandardCharsets.UTF_8 |
| BufferedReader.readLine() 吞掉換行符 | 文本處理邏輯錯誤 | 手動追加 \n 或使用 Files.readAllLines() |
| DataInputStream 讀取超出數據長度 | EOFException | 先寫入/讀取長度前綴,或捕獲異常處理 |
| 大文件一次性 readAllBytes() | OOM 內存溢出 | 分塊讀取、內存映射文件、流式處理 |
JDK 7+ 引入 java.nio.file.Files 與 Path,提供更簡潔的高層 API:
// 一次性讀取小文件
List lines = Files.readAllLines(path, StandardCharsets.UTF_8);
byte[] bytes = Files.readAllBytes(path);
// 大文件流式處理(自動關閉)
try (Stream stream = Files.lines(path)) {
stream.filter(s -> s.contains("ERROR")).forEach(System.out::println);
}
// 高性能複製/移動
Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
Java IO 流體系通過裝飾器模式實現了功能的靈活組合:基礎流負責數據源連接,緩衝流負責性能優化,轉換流負責編碼橋接,數據流負責類型序列化。理解包裝順序(由內而外:源 → 緩衝 → 功能增強 → 邏輯)與關閉順序(由外而內)是編寫高效、健壯 IO 代碼的關鍵。現代項目中,優先考慮 NIO.2 Files API 與 try-with-resources,僅在需要精細控制二進制協議時直接操作流層級 API。