DanceFire的专栏

天地不仁,以万物为刍狗

舞焰ID:DanceFire
262329次访问,排名223好友0人,关注者1
DanceFire的文章
原创 51 篇
翻译 4 篇
转载 0 篇
评论 928 篇
DanceFire的公告
最近评论
hqfmyway:出现过同样的问题,谢谢解惑!
phhwr85:非常感谢,正郁闷中!
herry0628:A gold website for wow gold and
buy wow gold sevise.
herry0628:A gold website for wow gold and
buy wow gold sevise.
herry0628:A gold website for wow gold and
buy wow gold sevise.
文章分类
收藏
    相册
    Unix家族族谱图
    编程语言家族族谱
    操作系统相关图片
    插图
    麒麟操作系统相关图片
    L4 微内核实现
    Fiasco - DROPS的底层微内核 (TU Dresden)
    L4Ka::Pistachio (UKa, UNSW)
    seL4 - Secure Embedded L4 (UNSW)
    L4 微内核研究组
    L4 总部
    UKa的L4研究组
    UNSW/NICTA的L4研究组
    L4 文档
    L4 X.2 API的用户手册(UNSW)
    L4-embedded 参考手册 N1 (UNSW)
    基于 L4 的操作系统
    Darwin在L4上的移植 - Darbat (UNSW)
    DROPS - 基于L4的嵌入式实时操作系统 (TU Dresden)
    GNU Hurd在L4上的移植
    Linux在L4上的移植 - L4Linux (TU Dresden)
    Linux在L4上的移植 - Wombat (UNSW)
    Mungi - Single Address Space OS based on L4 (UNSW)
    朋友
    Dancefire's website
    ralph623的专栏(RSS)
    sinboy的菜地(RSS)
    Sunwear(RSS)
    Xinsoft :应用之美,在于药到病除(RSS)
    吕震宇(RSS)
    强强专栏(RSS)
    旁观生活的BT(RSS)
    潇寒的Blog(RSS)
    龙真先生(RSS)
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 使用XmlWriter时请注意Encoding收藏

    新一篇: 让VS 2008支持Subversion | 旧一篇: Visual Studio 2008 LINQ to SQL 的Beta 2测试版和RTM正式版的差异

    这两天用一个常用编辑的软件打开一个最近更新的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();
            XmlWriterSettings setting = new XmlWriterSettings();
           setting.Encoding = new UTF8Encoding(false);
           setting.Indent = true;
        
    using (XmlWriter writer = XmlWriter.Create(stream, settings))
        
    {
            xs.Serialize(writer, site);
        }

        
    return Encoding.UTF8.GetString(stream.ToArray());


    这回输出就正常了。这里需要注意的是Encoding那一行,这是设置Encoding不要输出BOM,否则生成的字符串前会有几个字节表示Byte Order。

    因此,提醒诸位,如果使用非Stream类的输出,如StringBuilder/StringWriter,作为XmlWriter输出的话,请注意你的xml的Encoding。
     
    关于BOM,请参考:

    Byte Order Mark (BOM) FAQ
    http://unicode.org/faq/utf_bom.html#BOM


    Byte-order mark (wikipedia)
    http://en.wikipedia.org/wiki/Byte_Order_Mark

    发表于 @ 2007年12月02日 21:05:00|评论(loading...)|编辑

    新一篇: 让VS 2008支持Subversion | 旧一篇: Visual Studio 2008 LINQ to SQL 的Beta 2测试版和RTM正式版的差异

    评论

    #zxp319 发表于2008-05-20 18:53:25  IP: 121.28.132.*
    遇到类似问题

    收藏
    #herry0628 发表于2008-07-14 11:24:57  IP: 220.178.42.*
    A gold website for wow gold and
    buy wow gold sevise.
    #phhwr85 发表于2008-07-16 19:24:44  IP: 202.104.115.*
    非常感谢,正郁闷中!
    #hqfmyway 发表于2008-07-27 22:39:08  IP: 10.13.81.*
    出现过同样的问题,谢谢解惑!
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © DanceFire