xdocument.save() 默认带bom是因为encoding.utf8构造函数默认启用bom;解决方法是使用new utf8encoding(false)并调用save(stream, encoding)重载。

为什么 XDocument.Save() 生成的 XML 文件总带 BOM?
因为 .NET 默认用 Encoding.UTF8(即 new UTF8Encoding())写入,而这个构造函数默认启用 BOM。哪怕你显式传入 Encoding.UTF8,它底层仍是带 BOM 的实例——这不是 bug,是设计行为。
真实场景里,BOM 会导致:Linux 下脚本解析失败、某些 XML 解析器报 Invalid character at position 0、Git 提示文件“看似二进制”、CI 流水线校验不通过。
怎么让 XDocument.Save() 输出无 BOM 的 UTF-8?
必须绕过默认编码,手动指定一个不带 BOM 的 UTF8Encoding 实例,再传给 Save() 的重载版本。
- 用
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)构造编码器 - 调用
XDocument.Save(Stream, Encoding),而非Save(string)或Save(TextWriter) - 别用
File.WriteAllText()后续覆盖——那会重新引入 BOM
示例:
var doc = new XDocument(new XElement("root", new XElement("item", "test")));
using var fs = File.Create("output.xml");
doc.Save(fs, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
XmlWriter 方式更可控但容易漏掉设置
如果要用 XmlWriter(比如需要缩进、禁用空元素折叠等),BOM 控制点在 XmlWriterSettings.Encoding——同样得设成无 BOM 的 UTF8Encoding。
- 忘记设置
settings.Encoding,或误设为Encoding.UTF8,BOM 照样出现 -
XmlWriter.Create(string)不接受编码参数,必须用XmlWriter.Create(Stream, settings) - 缩进、换行等格式选项不影响 BOM,但和 BOM 一样,都依赖底层
Stream写入方式
示例:
var settings = new XmlWriterSettings {
Encoding = new UTF8Encoding(false),
Indent = true
};
using var writer = XmlWriter.Create("output.xml", settings);
doc.WriteTo(writer);
注意 FileStream 和 StreamWriter 的陷阱
直接用 StreamWriter 包裹 FileStream 再传给 XDocument.Save(TextWriter) 是常见错误路径——StreamWriter 的 Encoding 构造参数若没设 false,BOM 还是会回来。
-
new StreamWriter(fs, Encoding.UTF8)→ 带 BOM(Encoding.UTF8是静态只读实例) -
new StreamWriter(fs, new UTF8Encoding(false))→ 正确,但多此一举:不如直接用Save(Stream, Encoding) -
File.OpenWrite()返回的流不支持写入开头(如覆盖),建议用File.Create()或File.Open(..., FileMode.Create)
最简路径就是:Stream + 显式无 BOM 编码器 + XDocument.Save(Stream, Encoding)。
真正麻烦的不是怎么写,而是团队里有人改了某处 File.WriteAllText() 导出逻辑,又忘了配编码——这种散落各处的写法,比统一封装更难排查。







