前陣子團隊中有用XmlSerializer將物件轉成XML存檔後,上傳給另一家公司,對方卻一直回報我們XML有問題,用文字編輯器看格式都很正確,但用XML的編輯器卻會出錯,發現原來是BOM害的。
用Visual Studio開啟,會出現未預期的XML宣告。XML宣告必須是文件中的第一個節點,前面不得有空白字元的錯誤訊息(如圖一),可是怎麼看都沒有多餘的空白,後來用2進元編輯器開啟,發現檔案前多了一組BOM(Byte order mark)。
圖一 用Visual Studio開啟檔案所發生的錯誤。
圖二 多出的BOM。
NOTE:什麼是BOM
位元組順序記號(byte-order mark,BOM),是Unicode存放在檔案的最前面,用來記錄讀位元組的順序,如UTF-8是EF BB BF,詳情請看:
這是其中的程式碼片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var ser = new XmlSerializer(sample.GetType()); using ( var memoryStream = new MemoryStream()) { //XmlSerializer不給Encoding,其XML宣告會是UTF-16 var xmlWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); //空命名空間 XmlSerializerNamespaces xsn = new XmlSerializerNamespaces(); xsn.Add(String.Empty, String.Empty); ser.Serialize(xmlWriter, sample, xsn); var result = Encoding.UTF8.GetString(memoryStream.ToArray()); //do something //把檔案存起來 File.WriteAllText(filePath, result, Encoding.UTF8); } |
會照成輸入二次BOM的原因在於第5行與第17行,同時給了UTF8Encoding,但這不是最主要的原因,出錯的主因是二個地方都使用了有BOM的UTF8Encoding,查了MSDN,UTF8Encoding在建構式時,可以指定要不要輸出BOM,而System.Text.Encoding.UTF8是使用要輸出BOM的UTF8Encoding。
圖三 MSDN的UTF8Encoding的說明。
System.Text.Encoding.UTF8的原始碼
1 2 3 4 5 6 7 8 9 10 11 | public static Encoding UTF8 { get { if (utf8Encoding == null ) { utf8Encoding = new UTF8Encoding( true ); } return utf8Encoding; } } |
而System.Text.Encoding下的幾個靜態屬性UTF7、UTF8、Unicode、UTF32都是使用BOM為true的建構式,所以想不要BOM的話,請改用 new UTF8Encoding(false)。
NOTE:
我同時也看了File.WriteAllText的原始碼,其實是我們雞婆,因為File.WriteAllText的多載,其中File.WriteAllText(string path, string contents),所用的預設Encoding就是new UTF8Encoding(false),所以我們不指定Encoding反而沒事。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?