程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> 使用XmlWriter時請注意Encoding

使用XmlWriter時請注意Encoding

編輯:.NET實例教程

這兩天用一個常用編輯的軟件打開一個最近更新的xml配置文件時突然報編碼錯誤,說不支持utf-16。看到這個錯誤,我愣了一下,這個軟件不支持utf-16的xml我是知道的,但是這個xml配置文件可是用XmlSerializer序列化的一個class,一直都是使用utf-8編碼的,怎麼突然出utf-16了?用Notepad++打開這個XML,看了一下右下角的編碼,顯示的還是utf-8,看來文件輸出沒有錯啊,等等,突然注意到第一行:



<?XML version="1.0" encoding="utf-16"?>

咦?文件明明是utf-8,可是xml declaration怎麼成utf-16了?趕緊打開以前的XML配置文件對比了一下,發現早期的配置文件的encoding都是utf-8,而從某一天後,都是utf-16了。開始查閱SVN,翻看這段時間涉及到這個序列化的代碼變更,發現這段時間唯一可疑的變更就是之前的這個序列化是直接寫到文件裡的,之前的代碼形如:



    XmlSerializer xs = new XMLSerializer(typeof(Site));
    using (StreamWriter sw = new StreamWriter("output.XML"))
    ...{
        xs.Serialize(sw, site);
    }
    Console.WriteLine(File.ReadAllText("output.XML"));

但是後來由於數據庫也需要序列化後的結果,所以將序列化代碼移進這個類的ToString()了,之後的代碼形如:



    XmlSerializer xs = new XMLSerializer(typeof(Site));
    StringBuilder sb = new StringBuilder();
    using (XmlWriter writer = XMLWriter.Create(sb))
    ...{
        xs.Serialize(writer, site);
    }
    return sb.ToString();

其中唯一的區別就是一個使用的是TextWriter,而另一個用的是XmlWriter。難道說XMLWriter的Encoding默認是utf-16不成?不是啊,MSDN明明說:

The text encoding to use. The default is Encoding.UTF8.

好吧,我手動加入XMLWriterSettings,結果形如:



    XmlSerializer xs = new XMLSerializer(typeof(Site));
    StringBuilder sb = new StringBuilder();
    XmlWriterSettings settings = new XMLWriterSettings();
    settings.Encoding = Encoding.UTF8;
    settings.Indent = true;
    using (XmlWriter writer = XMLWriter.Create(sb, settings))
...{
        xs.Serialize(writer, site);
    }
    return sb.ToString();

手動將XmlWriter設置為utf-8,這回該好了吧?呵呵,如果好了就沒這篇Blog了。很不幸,依舊輸出encoding="utf-16"。見鬼了,難不成XMLWriter不支持utf-8?用腳趾頭也可以想象這不大可能。又翻開MSDN Library,好好看看到底問題在哪裡。

終於在XMLWriterSettings.Encoding的文檔裡面發現下面一段話:

This property only applIEs to XMLWriter instances that output text content to a stream; otherwise, this setting is ignored.

看來XmlWriter只支持在Stream類的輸出中設置Encoding。其實仔細想想也可以理解,只有stream類的輸出,Encoding才可以用來進行編碼,對於我們現在使用的StringBuilder來說,XML的輸出直接就變成了字符串了,沒有任何編碼過程,因此Encoding失效了。

可以說當我們使用StringBuilder的時候,StringBuilder的Encoding overwrite了XmlWriter的Encoding,而StringBuilder將會用StringWriter來包裝,StringWriter.Encoding是Encoding.Unicode,也就是utf-16。因此,當我們使用StringBuilder作為XmlWriter的輸出時,XmlWriter的Encoding就成了utf-16。而當我們把這個內存中的字符串,以utf-8寫入文件的時候,雖然此時編碼實際上為utf-8,但是並沒有人負責把XML聲明的encoding="utf-16"改回"utf-8"了。錯誤就這樣發生了。

問題明確了,解決起來並不復雜,我們用MemoryStream替換StringBuilder,形如:



    XmlSerializer xs = new XMLSerializer(typeof(Site));
    MemoryStream stream = new MemoryStream();
    using (XmlWriter writer = XMLWriter.Create(stream, settings))
    ...{
        xs.Serialize(writer, site);
    }
    return Encoding.UTF8.GetString(stream.ToArray());

這回輸出就正常了。

因此,提醒諸位,如果使用非Stream類的輸出,如StringBuilder/StringWriter,作為XmlWriter輸出的話,請注意你的XML的Encoding。
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved