首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 字元輸出流詳解:Writer、FileWriter、BufferedWriter 實戰指南

     編輯:Java 相關知識

字元流專為文字資料設計,自動處理編碼轉換。本文深入解析 Writer 體系、FileWriter、BufferedWriter 核心用法、編碼陷阱、try-with-resources 標準範本與效能優化技巧。

一、Writer 體系架構


java.io.Writer (abstract)
├── BufferedWriter          // 緩衝寫入,核心效能類
├── OutputStreamWriter      // 位元組→字元橋樑(指定 Charset)
│   └── FileWriter          // 便利類:預設編碼寫檔(JDK 11+ 可指定編碼)
├── CharArrayWriter         // 寫入字元陣列(記憶體緩衝)
├── StringWriter            // 寫入 StringBuffer
├── PipedWriter             // 執行緒管道輸出
└── PrintWriter             // 格式化列印,不拋 IOException

二、FileWriter:便利但有限

1. 建構子


// 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)

2. 核心方法


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()                         // 關閉並釋放檔案鎖

3. 範例:寫入 ASCII 可列印字元


try (FileWriter fw = new FileWriter("ascii.txt", StandardCharsets.UTF_8)) { // JDK 11+
    for (int i = 32; i < 127; i++) fw.write(i);
} // 自動 flush & close

三、BufferedWriter:生產環境必備

1. 為何需要緩衝?

  • 減少系統呼叫(JNI/系統中斷)次數,將多次小寫入合併為大塊寫入磁碟。
  • 預設緩衝區 8192 字元(16 KB),可自訂:new BufferedWriter(writer, 65536)。
  • 提供 newLine() 寫入**系統相關換行符**(Windows \r\n, Unix \n, Mac \r)。

2. 標準寫檔範本(指定 UTF-8,緩衝,自動關閉)


// 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();
        }
    }
}

3. 檔案複製範例(逐行讀寫)


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() 去除換行,寫入須補回
        }
    }
}

四、編碼陷阱與最佳實踐

  1. 永遠顯式指定 UTF-8:StandardCharsets.UTF_8。預設編碼隨 OS/VM 參數 (file.encoding) 變化,跨平台必亂碼。
  2. JDK 11 前 FileWriter 無法指定編碼**:舊專案必須用 OutputStreamWriter 包裝 FileOutputStream。
  3. 緩衝區未滿資料不落盤:關鍵時刻呼叫 flush(),或用 try-with-resources 保證 close() 觸發 flush。
  4. 大量寫入調大緩衝:new BufferedWriter(writer, 64 * 1024)。
  5. 追加模式:new FileWriter(file, true) 或 Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.APPEND)。

五、PrintWriter:格式化輸出的替代選擇


// 自動 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() 檢查。
  • 適合日誌、報表、人類可讀輸出。

六、NIO.2 Files 簡化 API (JDK 7+)


// 一行寫入列表(內部用 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() 處理跨平台換行,即可寫出健壯、高效的文字檔案處理代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved