如何避免File.WriteAllText写入双BOM?实现无BOM或单BOM写入
解决文件写入时的BOM重复问题
哈哈,这个BOM重复的坑我之前也踩过!核心问题在于:当你用encoding.GetString(bytes)把带BOM的响应字节转成字符串时,BOM会变成字符串开头的U+FEFF字符;而File.WriteAllText在使用支持BOM的编码(比如UTF-8、UTF-16)时,又会自动往文件开头加一个BOM,结果就出现了两个BOM的情况。
下面是两种需求的标准实现方式:
1. 写入完全不含BOM的文件
要彻底去掉BOM,得做两件事:先把字符串里的BOM字符删掉,再用不会自动添加BOM的编码版本来写入。
代码示例:
HttpWebResponse response = ... byte[] bytes = ... // 从响应获取的字节,可能包含BOM var encoding = Encoding.GetEncoding( response.CharacterSet, new EncoderExceptionFallback(), new DecoderExceptionFallback() ); // 第一步:移除字符串开头的BOM字符 string text = encoding.GetString(bytes); if (text.StartsWith('\uFEFF')) { text = text.Substring(1); } // 第二步:创建不生成BOM的编码实例 Encoding encodingWithoutBom; if (encoding is UTF8Encoding) { // UTF-8:false表示不生成BOM encodingWithoutBom = new UTF8Encoding(false); } else if (encoding is UnicodeEncoding) // UTF-16 { // 第二个参数控制是否生成BOM,false就是不生成 encodingWithoutBom = new UnicodeEncoding(encoding.IsLittleEndian, false); } else { // 对于ASCII这类本身不支持BOM的编码,直接用原编码即可 encodingWithoutBom = encoding; } // 写入文件,最终完全没有BOM System.IO.File.WriteAllText(fileName, text, encodingWithoutBom);
2. 写入仅含单个BOM的文件(编码适用时)
这种情况要确保最终只有一个BOM,所以得先删掉字符串里自带的BOM,再用会自动添加BOM的编码来写入。
代码示例:
HttpWebResponse response = ... byte[] bytes = ... // 从响应获取的字节,可能包含BOM var encoding = Encoding.GetEncoding( response.CharacterSet, new EncoderExceptionFallback(), new DecoderExceptionFallback() ); // 第一步:先把字符串里的BOM去掉,避免重复 string text = encoding.GetString(bytes); if (text.StartsWith('\uFEFF')) { text = text.Substring(1); } // 第二步:确保使用的编码会自动添加BOM Encoding encodingWithBom = encoding; if (encoding is UTF8Encoding utf8Enc && !utf8Enc.GetPreamble().Any()) { // 如果原UTF-8编码是无BOM版本,就换成带BOM的 encodingWithBom = new UTF8Encoding(true); } else if (encoding is UnicodeEncoding unicodeEnc && !unicodeEnc.GetPreamble().Any()) { // 同理,UTF-16换成带BOM的版本 encodingWithBom = new UnicodeEncoding(unicodeEnc.IsLittleEndian, true); } // 写入文件,编码会自动添加单个BOM System.IO.File.WriteAllText(fileName, text, encodingWithBom);
额外高效方案:直接操作字节流
如果不需要修改文本内容,直接处理字节会更高效(尤其是大文件),避免字符串转换的开销:
// 获取当前编码的BOM字节数组 byte[] preamble = encoding.GetPreamble(); byte[] bytesWithoutBom = bytes; // 检查原字节是否以BOM开头,是就移除 if (preamble.Length > 0 && bytes.Length >= preamble.Length) { bool hasBom = true; for (int i = 0; i < preamble.Length; i++) { if (bytes[i] != preamble[i]) { hasBom = false; break; } } if (hasBom) { bytesWithoutBom = bytes.Skip(preamble.Length).ToArray(); } } // 需求1:无BOM写入 File.WriteAllBytes(fileName, bytesWithoutBom); // 需求2:单个BOM写入 byte[] bytesWithSingleBom = preamble.Concat(bytesWithoutBom).ToArray(); File.WriteAllBytes(fileName, bytesWithSingleBom);
内容的提问来源于stack exchange,提问作者Exception e
相关产品推荐
相关产品推荐

