流 是有序數據序列的傳輸通道,屏蔽了底層設備差異(文件、網絡、內存、管道)。Java I/O 採用裝飾器模式,通過組合不同流類實現功能疊加。
| 輸入流 (讀) | 輸出流 (寫) | |
|---|---|---|
| 字節流 (8-bit) | InputStream | OutputStream |
| 字符流 (16-bit Unicode) | Reader | Writer |
轉換橋樑:InputStreamReader (字節→字符)、OutputStreamWriter (字符→字節),核心參數是 Charset。
FileInputStream, FileReader, ByteArrayInputStream, PipedInputStreamBufferedInputStream, DataInputStream, ObjectInputStream, BufferedReader, PrintWriter設計模式體現:`FilterInputStream` 為裝飾器基類,構造函數接收 `InputStream`,所有 `read()` 委托給被包裝流,子類覆寫增加邏輯(如緩衝、數據類型轉換)。
| 場景 | 推薦組合 | 關鍵點 |
|---|---|---|
| 高效讀寫文本文件 | BufferedReader / BufferedWriter | 行讀取 `readLine()`,默認 8KB 緩衝 |
| 高效讀寫二進制文件 | BufferedInputStream / BufferedOutputStream | 字節緩衝,減少系統調用 |
| 基本類型/字符串序列化 | DataInputStream / DataOutputStream | 按數據類型讀寫,跨平台一致 |
| 對象序列化 | ObjectInputStream / ObjectOutputStream | 實現 Serializable,注意 serialVersionUID |
| 格式化輸出控制台/文件 | PrintStream / PrintWriter | println/printf,不拋 IOException |
| 內存數據交換 | ByteArrayInputStream / ByteArrayOutputStream | 內存緩衝區,toByteArray() 獲取數據 |
| 進程/線程間通信 | PipedInputStream / PipedOutputStream | 配對使用,連接管道 |
| 隨機訪問文件 | RandomAccessFile | seek() 定位,read/write 同一對象,實現 DataInput/Output |
// ❌ 錯誤:依賴平台默認編碼,跨平台亂碼
new FileReader("file.txt");
new FileWriter("file.txt");
// ✅ 正確:顯式指定 UTF-8
new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8);
new OutputStreamWriter(new FileOutputStream("file.txt"), StandardCharsets.UTF_8);
// Java 11+ 更簡潔
Files.newBufferedReader(path, StandardCharsets.UTF_8);
Files.newBufferedWriter(path, StandardCharsets.UTF_8);
獲取系統默認編碼:`Charset.defaultCharset()` 或 `System.getProperty("file.encoding")`。
// Path 操作
Path path = Paths.get("/data", "logs", "app.log");
Path abs = path.toAbsolutePath();
Path rel = base.relativize(path);
Path resolved = path.resolveSibling("backup.log");
// 文件屬性
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
attrs.creationTime(); attrs.size(); attrs.isDirectory();
// 遍歷目錄樹 (流式、可並行)
Files.walk(root, 3) // 最大深度
.filter(p -> p.toString().endsWith(".log"))
.forEach(System.out::println);
// 複製/移動/刪除 (原子性選項)
Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
Files.move(src, dest, StandardCopyOption.ATOMIC_MOVE);
Files.deleteIfExists(path);
// 讀寫小文件 (一行代碼)
List lines = Files.readAllLines(path, StandardCharsets.UTF_8);
Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
// 大文件流式處理
try (Stream lines = Files.lines(path)) {
lines.filter(s -> s.contains("ERROR")).forEach(System.out::println);
}
不屬於流體系,直接繼承 `Object`,實現 `DataInput`/`DataOutput`。模式:"r" (只讀)、"rw" (讀寫)、"rws" (同步元數據)、"rwd" (同步數據)。
核心方法:seek(long pos) 移動文件指針,getFilePointer() 獲取當前位置,setLength(long len) 截斷/擴展文件。
現代替代:`FileChannel` + `MappedByteBuffer` (內存映射文件) 性能更優。
Java I/O 經歷了三代演進:BIO (流裝飾器) → NIO (Channel/Buffer/Selector) → NIO.2 (Path/Files/Async)。理解字節/字符轉換、裝飾器組合、緩衝機制、編碼指定、NIO.2 文件 API 是寫出健壯、高效 I/O 代碼的關鍵。現代項目以 NIO.2 為主,Netty 處理網絡,避免直接操作 Selector 和舊式流組合。