Java IO 體系中,字節流(Byte Stream)與字符流(Character Stream)是兩大核心支柱。理解它們的區別、轉換關係及適用場景,是高效處理文件、網絡、控制台輸入輸出的基礎。本文從底層原理到代碼實戰全方位解析。
| 維度 | 字節流 | 字符流 |
|---|---|---|
| 處理單元 | 單個字節(8 bit) | Unicode 碼元(char,16 bit) |
| 基類 | InputStream / OutputStream | Reader / Writer |
| 默認緩衝 | 無(需 BufferedInputStream) | 有(內部使用字節數組緩衝) |
| 典型用途 | 二進制數據(圖片、視頻、音頻、序列化對象) | 文本數據(TXT、XML、JSON、CSV、日誌) |
| 編碼轉換 | 不處理編碼 | 自動處理字符集編解碼(默認平台編碼或指定 Charset) |
public abstract int read() throws IOException; // 讀取單字節,-1 表示末尾
public int read(byte[] b) throws IOException; // 批量讀取,底層仍循環調用 read()
關鍵點:read(byte[]) 內部仍逐字節調用 read(),未利用內存緩衝,頻繁調用導致磁盤 IO 開銷大。必須包裝 BufferedInputStream 獲得性能提升。
字符流本質是 字節流 + 編碼轉換器:
因此字符流內部自帶緩衝區,累積轉換後的字節再批量寫入,效率高於裸字節流。
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt");
fw.write("demo");
} finally {
if (fw != null) fw.close();
}
}
}
未指定編碼時,使用平台默認編碼(Windows 為 GBK,Linux 為 UTF-8)。生成的 demo.txt 十六進制為 64 65 6D 6F(ASCII/UTF-8 編碼)。
橋梁類:InputStreamReader、OutputStreamWriter。
// 字節流 → 字符流(指定 UTF-8 編碼)
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8));
// 字符流 → 字節流
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("out.txt"), StandardCharsets.UTF_8));
最佳實踐:始終顯式指定 StandardCharsets.UTF_8,避免跨平台亂碼。
// 讀取所有行(自動關閉流)
List<String> lines = Files.readAllLines(Paths.get("data.txt"), StandardCharsets.UTF_8);
// 寫入文本
Files.write(Paths.get("out.txt"), "內容".getBytes(StandardCharsets.UTF_8));
Files、Paths API 更簡潔、支持符號鏈接、屬性讀取,推薦新項目優先使用。
字節流處理原始二進制,字符流封裝編碼轉換並內建緩衝。實際開發中:文本用字符流(指定 UTF-8),二進制用字節流(加緩衝),轉換靠 Bridge 類,新項目優先考慮 java.nio.file.Files。牢記這條主線,IO 處理不再迷茫。