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

Encoding 如何最好地检测XML文件中的编码?,encoding,linq-to-xml,xmlreader,xelement,Encoding,Linq To Xml,Xmlreader,Xelement,要加载任意编码的XML文件,我有以下代码: Encoding encoding; using (var reader = new XmlTextReader(filepath)) { reader.MoveToContent(); encoding = reader.Encoding; } var settings = new XmlReaderSettings { NameTable = new NameTable() }; var xmlns = new XmlNamesp

要加载任意编码的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);
}
这是可行的,但是两次打开文件似乎有点低效。是否有更好的方法来检测编码,以便我可以:

  • 打开文件
  • 检测编码
  • 将XML读入XElement
  • 关闭文件

  • 好的,我应该早点想到这个。XmlTextReader(它为我们提供了编码)和XmlReader.Create(它允许我们指定编码)都接受流。那么,首先打开一个文件流,然后将其与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文件应该更加优雅,但至少我只打开了一个文件。

    另一个非常简单的选择是使用Linq to XML。Load方法自动从xml文件中读取编码。然后可以使用属性获取编码器值。 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);
    

    虽然这可能无法满足原始海报的要求,因为他必须重构大量代码,但对于那些必须为项目编写新代码的人来说,或者如果他们认为重构值得的话,这是很有用的。

    在检测编码方面,调用重载是否也会起到同样的作用?@petrk.-我显式地使用XmlTextReader,因为它是提供
    编码属性的类。不知道你还有什么想法?好的,让我解释一下。似乎
    XElement.Load(XmlReader.Create(newfilestream(filepath,FileMode.Open))
    应该做一些事情(为了简洁起见省略了处理资源)。文档说明:XmlReader扫描流的第一个字节,寻找字节顺序标记或其他编码符号。确定编码后,将使用编码继续读取流,处理将继续将输入解析为(Unicode)字符流。我想知道您的显式编码检测是否与XmlReader.Create(Stream)重载有什么不同。@petrk。有趣的。。。我确信当时的情况是,
    XmlReader
    本身无法工作,我必须通过解析器上下文显式指定编码才能工作。我应该在这里记录更多的场景,因为现在我记不起所有细节:)