DanceFire的专栏
天地不仁,以万物为刍狗
登录
注册
全站
当前博客
空间
博客
好友
相册
留言
使用XmlWriter时请注意Encoding
收藏
这两天用一个常用编辑的软件打开一个最近更新的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正式版的差异
用户操作
[即时聊天]
[发私信]
[加为好友]
DanceFire
订阅我的博客
DanceFire的公告
文章分类
C#/Java
C++
Idea
Networking
Operating System
Security
非技术
自然语言处理
收藏
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)
存档
2009年02月(1)
2007年12月(2)
2007年11月(3)
2007年05月(2)
2007年04月(3)
2006年09月(3)
2006年07月(3)
2006年06月(3)
2006年05月(11)
2006年04月(3)
2006年03月(6)
2005年12月(1)
2005年11月(2)
2004年10月(13)