【发布时间】:2017-06-18 16:36:24
【问题描述】:
我在这里遇到了一个非常奇怪的问题:我正在构建一个第三方系统的接口,该系统通过 SFTP 服务器提供 XML 文件(使用 UTF-8 编码)。
我在我的 C# 代码中下载这些文件,然后尝试将它们反序列化为 C# 对象。对于大多数文件来说,这很好用,但对于某些文件来说,它只是不断轰炸......
想象一下这样的 DTO 类:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
还有这样的 XML:
<?xml version="1.0" encoding="utf-8"?>
<Person>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Age>42</Age>
</Person>
我在 C# 代码中所做的是:
- 从 SFTP 服务器下载文件内容为字节数组
- 从该二进制数据中提取一个 UTF-8 编码的字符串
- 在反序列化过程中使用该字符串表示
类似这样的:
// get bytes from SFTP server
byte[] content = _sftpClient.Download(fileName);
// convert content to a UTF-8 string
string contentAsString = Encoding.UTF8.GetString(content);
try
{
// deserialize that string into a "Person" instance
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreProcessingInstructions = true;
settings.IgnoreWhitespace = true;
settings.CheckCharacters = false;
using (StringReader str = new StringReader(contentAsString))
using (XmlReader xr = XmlReader.Create(str, settings))
{
XmlSerializer ser = new XmlSerializer(typeof(Person));
if (ser.CanDeserialize(xr))
{
Person person = ser.Deserialize(xr) as Person;
}
}
}
catch (Exception exc)
{
Console.WriteLine("ERROR: {0} - {1}", exc.GetType().Name, exc.Message);
}
现在我分析了有效的文件和无效的文件 - 区别在于二进制数据 (0xEF 0xBB 0xBF) 中的三字节前缀 - “Unicode BOM”(字节顺序标记)。
我知道 BOM,这就是我不使用直接从 SFTP 服务器获取的 二进制 数据的原因。当我将这些类型的文件转换为 XML 字符串 contentAsString 时,这个字符串 似乎 是相同的 - 至少我看不出有任何区别。
但是以 3 字节 BOM 开头的文件(在二进制数据中)导致反序列化在这一行失败
if (ser.CanDeserialize(xr))
出现错误:
SystemException:根级别的数据无效。第 1 行,位置 1。
但是 string 究竟是如何知道/“保存”关于 3 字节 BOM 的信息的呢?我期待通过将字节数组转换为 UTF-8 编码字符串,任何差异都会消失,BOM 应该不再相关......
关于如何可靠地处理 with 或 没有 3 字节 BOM 的文件的任何想法?
【问题讨论】:
-
可能重复 - 看看这个答案:stackoverflow.com/questions/3104158/…
-
@hoodaticus 这不是完全重复的 - 是的,情况似乎几乎相同 - 但接受的响应实际上是我已经在做的事情,而且它不起作用 对我来说(如果存在 BOM,则会导致异常)。不幸的是,该提议的解决方案并没有解决我的问题.....
-
BOMbing out 我知道你在那里做了什么:-D
标签: c# xml utf-8 deserialization