如何最好地检测XML文件的编码?

8
为了加载任意编码的XML文件,我有以下代码:

Encoding encoding;
using (var reader = new XmlTextReader(filepath))
{
    reader.MoveToContent();
    encoding = reader.Encoding;
}

var settings = new XmlReaderSettings { NameTable = new NameTable() };
var xmlns = new XmlNamespaceManager(settings.NameTable);
var context = new XmlParserContext(null, xmlns, "", XmlSpace.Default, 
    encoding);
using (var reader = XmlReader.Create(filepath, settings, context))
{
    return XElement.Load(reader);
}

这样做是可行的,但打开文件两次似乎有点低效。是否有更好的方法可以检测编码,以便我可以执行以下操作:

  1. 打开文件
  2. 检测编码
  3. 将XML读入XElement中
  4. 关闭文件
2个回答

9

好的,我应该早点想到这个方法。XmlTextReader(它提供了编码)和XmlReader.Create(它允许我们指定编码)都接受一个流。那么我们可以先打开一个FileStream,然后将其与XmlTextReader和XmlReader一起使用,就像这样:

using (var txtreader = new FileStream(filepath, FileMode.Open))
{
    using (var xmlreader = new XmlTextReader(txtreader))
    {
        // Read in the encoding info
        xmlreader.MoveToContent();
        var encoding = xmlreader.Encoding;

        // Rewind to the beginning
        txtreader.Seek(0, SeekOrigin.Begin);

        var settings = new XmlReaderSettings { NameTable = new NameTable() };
        var xmlns = new XmlNamespaceManager(settings.NameTable);
        var context = new XmlParserContext(null, xmlns, "", XmlSpace.Default,
                 encoding);

        using (var reader = XmlReader.Create(txtreader, settings, context))
        {
            return XElement.Load(reader);
        }
    }
}

这个方法非常有效。以一种与编码无关的方式读取XML文件可能更加优雅,但至少我只需要打开一个文件就行了。

仅调用XmlReaderCreate(Stream)重载是否在检测编码方面起到相同的作用? - petr k.
@petrk - 我明确地使用XmlTextReader,因为它提供“Encoding”属性。不确定你还有什么想法? - Peter Lillevold
好的,让我解释一下。看起来 XElement.Load(XmlReader.Create(new FileStream(filepath, FileMode.Open))) 应该做同样的事情(为了简洁起见省略了资源处理)。XmlReader.Create(Stream) 的文档说:XmlReader 扫描流的前几个字节,寻找字节顺序标记或其他编码标志。当确定编码时,就使用该编码继续读取流,并且处理将继续将输入解析为(Unicode)字符流。 我想知道您是否明确指定了编码类型。 - petr k.
@petrk. 有趣... 我记得以前有过一种情况,仅使用 XmlReader 无法工作,我必须通过解析器上下文明确指定编码才能使它工作。我应该在这里记录更多我的情境,因为现在我无法记住所有的细节 :) - Peter Lillevold
@petrk. - 确保的唯一方法是使用各种编码的文件构建一些测试用例。 - Peter Lillevold
显示剩余2条评论

0

另一个相当简单的选项是使用 Linq to XML。Load 方法会自动从 xml 文件中读取编码。然后,您可以通过使用 XDeclaration.Encoding 属性来获取编码器值。 以下是 MSDN 上的示例:

// Create the document
XDocument encodedDoc16 = new XDocument(
new XDeclaration("1.0", "utf-16", "yes"),
new XElement("Root", "Content")
);
encodedDoc16.Save("EncodedUtf16.xml");
Console.WriteLine("Encoding is:{0}", encodedDoc16.Declaration.Encoding);
Console.WriteLine();

// Read the document
XDocument newDoc16 = XDocument.Load("EncodedUtf16.xml");
Console.WriteLine("Encoded document:");
Console.WriteLine(File.ReadAllText("EncodedUtf16.xml"));
Console.WriteLine();
Console.WriteLine("Encoding of loaded document is:{0}", newDoc16.Declaration.Encoding);

虽然这可能对原帖发布者没有帮助,因为他需要重构大量代码,但对于那些需要为自己的项目编写新代码或认为重构值得的人来说,这是有用的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接