字元流專為文字資料設計,自動處理編碼轉換。本文深入解析 Writer 體系、FileWriter、BufferedWriter 核心用法、編碼陷阱、try-with-resources 標準範本與效能優化技巧。
java.io.Writer (abstract)
├── BufferedWriter // 緩衝寫入,核心效能類
├── OutputStreamWriter // 位元組→字元橋樑(指定 Charset)
│ └── FileWriter // 便利類:預設編碼寫檔(JDK 11+ 可指定編碼)
├── CharArrayWriter // 寫入字元陣列(記憶體緩衝)
├── StringWriter // 寫入 StringBuffer
├── PipedWriter // 執行緒管道輸出
└── PrintWriter // 格式化列印,不拋 IOException
// JDK 11+ 才支援指定編碼,舊版**無法指定編碼**(預設平台編碼,極易亂碼)
FileWriter(String fileName)
FileWriter(String fileName, boolean append) // true = 追加模式
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(FileDescriptor fd)
// JDK 11+ 新增
FileWriter(String fileName, Charset charset)
FileWriter(String fileName, Charset charset, boolean append)
FileWriter(File file, Charset charset)
FileWriter(File file, Charset charset, boolean append)
write(int c) // 單字元
write(char[] cbuf) // 字元陣列
write(char[] cbuf, int off, int len)
write(String str)
write(String str, int off, int len)
append(CharSequence csq) // 實作 Appendable,支援鏈式
flush() // 強制刷新緩衝區
close() // 關閉並釋放檔案鎖
try (FileWriter fw = new FileWriter("ascii.txt", StandardCharsets.UTF_8)) { // JDK 11+
for (int i = 32; i < 127; i++) fw.write(i);
} // 自動 flush & close
new BufferedWriter(writer, 65536)。newLine() 寫入**系統相關換行符**(Windows \r\n, Unix \n, Mac \r)。
// JDK 11+ 推薦寫法
public void writeLines(Path path, List lines) throws IOException {
try (BufferedWriter bw = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
for (String line : lines) {
bw.write(line);
bw.newLine(); // 跨平台換行
}
}
}
// JDK 8 相容寫法
public void writeLinesLegacy(File file, List lines) throws IOException {
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) {
for (String line : lines) {
bw.write(line);
bw.newLine();
}
}
}
public void copyTextFile(File src, File dst) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(src), StandardCharsets.UTF_8));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dst), StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine(); // 關鍵:readLine() 去除換行,寫入須補回
}
}
}
StandardCharsets.UTF_8。預設編碼隨 OS/VM 參數 (file.encoding) 變化,跨平台必亂碼。OutputStreamWriter 包裝 FileOutputStream。flush(),或用 try-with-resources 保證 close() 觸發 flush。new BufferedWriter(writer, 64 * 1024)。new FileWriter(file, true) 或 Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.APPEND)。
// 自動 flush 行尾(啟用 autoFlush)
try (PrintWriter pw = new PrintWriter(
new OutputStreamWriter(new FileOutputStream("fmt.txt"), StandardCharsets.UTF_8), true)) {
pw.println("Line 1"); // 自動換行 + flush
pw.printf("Value: %d, Hex: %X%n", 42, 42); // 格式化
pw.format("Pi = %.5f%n", Math.PI);
}
IOException,需呼叫 checkError() 檢查。
// 一行寫入列表(內部用 BufferedWriter)
Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
// 一行追加
Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.APPEND);
// 取得 BufferedWriter 手動控制
try (BufferedWriter bw = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) { ... }
字元輸出流的核心是 **編碼指定 + 緩衝包裝 + try-with-resources**。拋棄無編碼的 FileWriter,統一使用 Files.newBufferedWriter (JDK 11+) 或 OutputStreamWriter + BufferedWriter (JDK 8),並善用 newLine() 處理跨平台換行,即可寫出健壯、高效的文字檔案處理代碼。