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

JDOM 輸出 UTF-8 XML 亂碼終極解決方案:Writer vs Stream 的陷阱

     編輯:Java 相關知識

現象:明明設置 UTF-8 卻亂碼

使用 JDOM XMLOutputter 輸出 XML 時,控制台或文件出現亂碼,即使調用 format.setEncoding("UTF-8") 也無效。網上流傳各種「設置 Format」「加 BOM」偏方,實則治標不治本。

根因:JDK 流體系的編碼轉換機制

XMLOutputter 提供兩組輸出方法:

  • output(Document, OutputStream) — 字節流,**由 JDOM 內部按指定編碼寫入**
  • output(Document, Writer) — 字符流,**編碼由 Writer 構造時決定**,JDOM 無法干預

核心誤區:以為 Format.setEncoding() 能控制 Writer 輸出編碼。實際上,Writer 一旦構造完成,其編碼已鎖死(FileWriter 默認平台編碼,PrintWriter(System.out) 默認控制台編碼),JDOM 僅將字符傳給 Writer,無法改變其編碼行為。

正確姿勢:分場景選擇流類型

場景一:輸出到文件 → 必須用 OutputStream

// ❌ 錯誤:FileWriter 默認平台編碼(Windows 通常是 GBK),導致 UTF-8 字符被錯誤編碼
FileWriter fw = new FileWriter("out.xml");
outputter.output(doc, fw);

// ✅ 正確:FileOutputStream 由 JDOM 按 Format 指定編碼寫入
FileOutputStream fos = new FileOutputStream("out.xml");
outputter.output(doc, fos); // 此時 setEncoding("UTF-8") 生效

場景二:輸出到控制台 → 必須用 PrintWriter 包裝 System.out

// ❌ 錯誤:System.out 是 PrintStream,編碼為控制台編碼(Windows cmd 為 GBK)
outputter.output(doc, System.out);

// ✅ 正確:PrintWriter 构造时指定編碼,或使用不轉碼的 PrintWriter
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"), true);
outputter.output(doc, pw);

// 簡化寫法(JDK 1.5+):PrintWriter 支持直接指定編碼
PrintWriter pw = new PrintWriter(System.out, true, "UTF-8"); // autoFlush=true
outputter.output(doc, pw);

場景三:輸出到字符串 → 用 StringWriter 但注意無編碼概念

StringWriter sw = new StringWriter();
outputter.output(doc, sw); // 字符串無編碼,直接獲取內容
String xml = sw.toString();

驗證代碼:一鍵排查

public class JdomUtf8Demo {
    public static void main(String[] args) throws Exception {
        File xmlFile = new File("test.xml");
        
        Element root = new Element("root");
        root.addContent(new Element("item").setText("中文測試"));
        Document doc = new Document(root);
        
        XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
        // Format 默認編碼即 UTF-8,無需顯式 setEncoding
        
        // 文件輸出:用 FileOutputStream
        try (FileOutputStream fos = new FileOutputStream(xmlFile)) {
            outputter.output(doc, fos);
        }
        
        // 控制台輸出:用指定編碼的 PrintWriter
        try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"), true)) {
            outputter.output(doc, pw);
        }
    }
}

深度解析:為什麼 FileWriter 不行?

FileWriter 繼承 OutputStreamWriter,構造時**強制使用平台默認編碼**(Charset.defaultCharset()),且**無構造參數可覆蓋**。JDK 設計如此是為了「開箱即用」,但犧牲了編碼控制權。任何需要指定編碼的文件寫入,均應直接用 FileOutputStream + OutputStreamWriter 或 JDOM 直接接受 OutputStream。

總結口訣

文件用 Stream,控制台用 Writer(指定編碼),字符串用 StringWriter。
Format.setEncoding() 只對 OutputStream 生效,對 Writer 無效。

徹底理解 JDK 流體系編碼邊界,JDOM UTF-8 輸出不再是玄學。

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