XML BOM头是什么 如何处理带BOM的XML文件

BOM是文件开头用于标识编码的特殊字节,UTF-8中为EF BB BF;XML解析时易因BOM误读报“前言中不允许有内容”错误;安全读取需先探测再跳过BOM,推荐用BOMInputStream或手动跳过,避免FileReader;生成XML时应显式指定UTF-8编码以防写入BOM。

BOM(Byte Order Mark,字节顺序标记)是加在文本文件开头的一组特殊字节,用于标识文件的编码方式。对UTF-8来说,BOM是固定的三个字节 EF BB BF;虽然UTF-8本身不依赖字节序,但这个标记可被解析器用来明确识别“这是UTF-8编码”,不过XML规范其实不推荐在UTF-8 XML中使用BOM——因为部分解析器(如Dom4j、JDOM、Xerces等)会把BOM误读为文档内容,导致报错“Content is not allowed in prolog”。

XML解析时BOM引发的典型错误

常见现象包括:

  • 解析器报错:第一行出现乱码字符(如),或直接提示“前言中不允许有内容”
  • 用十六进制工具(如UltraEdit、xxd)查看文件开头,可见ef bb bf(UTF-8 BOM)或ff fe(UTF-16LE)、fe ff(UTF-16BE)
  • FileReader这类默认编码读取时失败——因为它不识别BOM,会把BOM当普通字符读入

Java中安全读取带BOM的XML文件

核心思路是:先探测BOM,再按实际编码读取,跳过BOM字节。推荐以下几种方式:

  • 用Apache Commons IO的BOMInputStream(最稳妥):
    它自动检测并跳过BOM,并通过getBOMCharsetName()返回真实编码名,后续可传给InputStreamReader
  • 手动探测+跳过:用FileInputStream读前3字节,判断是否为EF BB BF;若是,构造new UTF8Encoding(false).getString(buffer, 3, len-3)(.NET风格)或用new String(bytes, 3, bytes.length-3, "UTF-8")(Java)
  • 避免用FileReader:它不支持BOM处理,且依赖系统默认编码,极易出错;一律改用InputStreamReader配合明确指定的Charset

生成XML时避免写入BOM

如果你用Java写XML文件(比如用Transformer、DOM或JAXB输出),默认不会写BOM——但某些Windows编辑器(如记事本)另存为UTF-8时会自动添加。防范措施:

  • OutputStreamWriter写入时,显式指定StandardCharsets.UTF_8(Java 7+),它不会写BOM
  • 若必须兼容旧工具,可用Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE),同样无BOM
  • 避免用FileWriter——它不接受编码参数,行为不可控

快速验证与修复脚本(命令行辅助)

开发中可快速确认和清理BOM:

  • 检查BOM:file -i your.xmlhexdump -C your.xml | head -n 1
  • 移除BOM(Linux/macOS):tail -c +4 your.xml > no_bom.xml(跳过前3字节)
  • 批量清理(Python一行):for f in *.xml; do sed -i '1s/^\xEF\xBB\xBF//' "$f"; done
不复杂但容易忽略