Java IO 體系中,字節流與字符流是兩大核心支柱。搞清它們的區別、轉換關係及適用場景,是處理文件讀寫、網絡通訊、數據序列化等任務的基礎。本文從原理、代碼實戰、常見坑點三個維度深度解析,助你構建清晰的 IO 知識體系。
| 維度 | 字節流 | 字符流 |
|---|---|---|
| 頂層抽象類 | InputStream / OutputStream |
Reader / Writer |
| 處理單位 | 1 字節 | 2 字節 Unicode 字符 |
| 核心用途 | 二進制數據:圖片、音視頻、壓縮包、網絡傳輸 | 文本數據:TXT、XML、JSON、屬性文件、中文處理 |
| 編碼轉換 | 無,直接操作原始字節 | 內部自動按 JVM 默認或指定編碼轉換 |
| 典型實現類 | FileInputStream、FileOutputStream |
FileReader、FileWriter |
字節流與字符流的轉換關鍵在於編碼:
InputStreamReader 讀取字節,按指定編碼解碼為字符OutputStreamWriter 將字符按指定編碼編碼為字節輸出// 字節流轉字符流(讀取文本文件,指定 UTF-8 編碼)
FileInputStream fis = new FileInputStream("data.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr); // 加緩衝提升性能
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
// 字符流轉字節流(寫入文本文件,指定 UTF-8 編碼)
FileOutputStream fos = new FileOutputStream("out.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
bw.write("Hello 世界");
bw.newLine();
bw.close();
核心原理:
String(byte[] bytes, String charsetName)— 字節數組按編碼解碼為字符串
String.getBytes(String charsetName)— 字符串按編碼編碼為字節數組
public static void copyBinaryFile(String src, String dest) throws IOException {
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dest)) {
byte[] buffer = new byte[8192];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
}
public static void processTextFile(String src, String dest) throws IOException {
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream(src), "UTF-8"));
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(dest), "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
// 業務處理:如過濾、轉換、統計等
bw.write(line.toUpperCase());
bw.newLine();
}
}
}
BufferedInputStream/BufferedReader,減少系統調用開銷。Java IO 大量使用裝飾者模式靈活組合功能:
// 基礎節點流
FileInputStream fis = new FileInputStream("file.dat");
// 套裝飾者:緩衝 -> 數據類型讀取 -> 對象序列化
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
ObjectInputStream ois = new ObjectInputStream(dis);
// 同理輸出端
FileOutputStream fos = new FileOutputStream("file.dat");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
ObjectOutputStream oos = new ObjectOutputStream(dos);
這種設計讓「數據源」與「處理邏輯」解耦,靈活應對各種場景組合。
FileChannel、MappedByteBuffer) 或零拷貝掌握字節流與字符流的本質區別,就是掌握了 Java IO 的「第一性原理」。實戰中根據數據性質選擇正確流類型,顯式指定編碼,善用緩衝與 try-with-resources,即可寫出健壯、高效的 IO 代碼。