處理文本檔案時,需將位元組流(`InputStream`/`OutputStream`)轉為字元流(`Reader`/`Writer`)以正確解碼編碼。本文對比兩種標準轉換方式、緩衝層疊加、資源關閉順序與編碼陷阱。
FileInputStream fis = new FileInputStream("c:/abc.txt"); // 位元組流
InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); // 指定編碼轉字元流
BufferedReader br = new BufferedReader(isr); // 疊加緩衝,支援 readLine()
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
// 關閉順序:從外層往內層
br.close();
isr.close();
fis.close();
優勢:顯式指定 `Charset`,避免平台預設編碼不一致導致亂碼;可包裝任何 `InputStream`(網路、記憶體、壓縮流)。
FileReader fr = new FileReader("c:/abc.txt"); // 內部預設平台編碼
BufferedReader br = new BufferedReader(fr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
fr.close();
缺點:無法指定編碼,依賴 `file.encoding` 系統屬性,跨平台部署極易亂碼;JDK 11+ 內部改用 `InputStreamReader` 但仍不暴露編碼參數。
// 推薦:指定編碼
FileOutputStream fos = new FileOutputStream("out.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
bw.write("中文測試");
bw.newLine();
bw.close();
// 不推薦:FileWriter 無法指定編碼
try (FileInputStream fis = new FileInputStream("c:/abc.txt");
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} // 自動按相反順序關閉,即使發生異常也保證釋放
// 一行代碼讀取所有行,自動 UTF-8,自動關閉
List<String> lines = Files.readAllLines(Paths.get("c:/abc.txt"), StandardCharsets.UTF_8);
// 串流處理大檔案,記憶體友善
try (Stream<String> stream = Files.lines(Paths.get("c:/abc.txt"), StandardCharsets.UTF_8)) {
stream.forEach(System.out::println);
}
掌握位元組流與字元流轉換本質,堅持顯式指定編碼、善用 try-with-resources,是寫出健壯 IO 代碼的關鍵。