Java IO 是基礎且核心的模塊,掌握流體系架構、緩衝機制、序列化協議、資源管理是寫出高效穩健代碼的前提。本文提煉核心知識點,對比字節/字符流、節點/處理流,給出生產級使用規範。
| 維度 | 字節流 (8-bit) | 字符流 (16-bit Unicode) |
| 抽象基類 | InputStream / OutputStream | Reader / Writer |
| 典型節點流 | FileInputStream、ByteArrayInputStream | FileReader、CharArrayReader |
| 核心處理流 | BufferedInputStream、DataInputStream、ObjectInputStream | BufferedReader、InputStreamReader(橋接) |
| 適用場景 | 圖片、視頻、二進制協議、序列化 | 文本文件、配置、網頁、JSON/XML |
文件對象核心操作
File f = new File("path/to/file.txt");
// 存在性判斷 (必須先判斷)
if (!f.exists()) return;
// 類型判斷
boolean isDir = f.isDirectory();
boolean isFile = f.isFile();
// 常用屬性
String parent = f.getParent(); // 父目錄絕對路徑,相對路徑可能返回 null
String separator = File.separator; // 平台分隔符 (Win \, Unix /)
long length = f.length(); // 文件大小(字節)
long lastModified = f.lastModified(); // 最後修改時間戳
// 創建/刪除
f.createNewFile(); // 原子創建,存在返回 false
f.deleteOnExit(); // JVM 退出時刪除 (臨時文件清理)
f.mkdirs(); // 遞歸創建目錄
// 列舉/過濾
File[] files = f.listFiles((dir, name) -> name.endsWith(".txt")); // Lambda 過濾
// 等價 FilenameFilter 匿名類
緩衝機制核心原則
- 本質:內部封裝字節/字符數組 (默認 8KB),批量讀寫減少系統調用
- 構造:必須包裝節點流
new BufferedInputStream(new FileInputStream(file))
- 關鍵操作:
flush():強制將緩衝區數據寫入底層流 (輸出流)
close():隱式 flush + 釋放底層流資源
- BufferedReader 特有:
readLine() 讀取一行 (不含換行符),返回 null 表示 EOF
緩衝區大小調優
// 大文件順序讀寫可調大緩衝區 (64KB-256KB)
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src), 131072);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dst), 131072)) {
byte[] buf = new byte[131072];
int len;
while ((len = bis.read(buf)) != -1) bos.write(buf, 0, len);
}
數組流特殊性
ByteArrayInputStream:構造需傳入 byte[] 作為數據源
ByteArrayOutputStream:構造無需目標,內部維護可擴展 byte[]
- 無需 close():不佔用系統資源 (文件句柄、Socket),GC 自動回收內存
- 常用於:內存序列化、壓縮/加密中轉、測試模擬
序列化核心協議
實現條件
- 實現
Serializable 標記接口 (無方法)
- 建議顯式聲明
private static final long serialVersionUID = 1L;
字段處理規則
| 修飾符 | 是否序列化 | 說明 |
| 普通實例字段 | ✅ 是 | 遞歸序列化對象圖 |
static | ❌ 否 | 屬於類,不屬於實例 |
transient | ❌ 否 | 敏感數據(密碼)、非序列化資源(連接、鎖)、衍生字段 |
final (基本類型/字符串) | ✅ 是 | 編譯期常量內聯,實例常量正常序列化 |
自定義序列化 (高級)
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // 默認序列化非 transient 字段
out.writeObject(derivedField); // 手動序列化衍生字段
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
derivedField = (DerivedType) in.readObject(); // 手動反序列化
recomputeDerived(); // 重新計算
}
標準流與編碼橋接
// 標準流 (已關聯控制台)
InputStream in = System.in; // 鍵盤輸入
PrintStream out = System.out; // 螢幕輸出
PrintStream err = System.err; // 錯誤輸出
// 重定向
System.setIn(new FileInputStream("input.txt"));
System.setOut(new PrintStream(new FileOutputStream("out.log")));
// 字節轉字符橋接 (指定編碼)
BufferedReader br = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8), true); // autoFlush
生產級使用清單
- try-with-resources:所有流操作**強制**使用 (JDK 7+)
- 顯式編碼:
StandardCharsets.UTF_8,拒絕平台預設
- 緩衝包裝:讀寫文本必用
BufferedReader/Writer,二進制用 BufferedInput/OutputStream
- 大文件流式:嚴禁
readAllBytes()/Files.readString() 載入超大文件
- 序列化慎用:跨語言/長期存儲優先 JSON/Protobuf/Avro,Java 內部臨時傳輸可用
- 關閉順序:外層處理流先關閉 (自動關閉內層),或 try-with-resources 自動管理
NIO.2 現代替代 (JDK 7+)
// 文件操作
Files.copy(src, dst, REPLACE_EXISTING);
Files.move(src, dst, ATOMIC_MOVE);
Files.deleteIfExists(path);
Files.walkFileTree(root, visitor); // 遍歷
// 文本便捷
List lines = Files.readAllLines(path, UTF_8); // 小文件
Files.write(path, lines, UTF_8, APPEND);
try (Stream lines = Files.lines(path, UTF_8)) { /* 流式處理 */ }
// 二進制流式
try (InputStream is = Files.newInputStream(path);
OutputStream os = Files.newOutputStream(dst, CREATE, APPEND)) { /* 複製 */ }
總結
Java IO 核心在於**「流的裝飾鏈」設計模式**:節點流接觸數據源,處理流疊加功能 (緩衝、轉換、對象化)。理解字節/字符分界、緩衝批量原理、序列化字段語義、資源確定性釋放,配合 NIO.2 便捷 API,即可應對 95% IO 場景。牢記:無緩衝不讀寫、無編碼不轉換、無 try-with-resources 不開流。
- 上一篇文章: Java 類與對象初始化順序深度解析:靜態/實例字段、代碼塊、構造器執行流程
- 下一篇文章: Java int 與 Integer 區別深度解析:基本類型、包裝類、自動拆裝箱與緩存機制
Copyright ©
程式碼之家 All Rights Reserved