2009-03-12 2 views
7

Для загрузки XML-файлов с произвольным кодированием у меня есть следующий код:Как лучше всего обнаружить кодировку в 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. Open file 
2. Detect encoding 
3. Read XML into an XElement 
4. Close file 

ответ

8

Хорошо, мне следовало подумать об этом раньше. И XmlTextReader (который дает нам кодировку), так и XmlReader.Create (который позволяет нам указывать кодировку) принимает Stream. Так как насчет первого открытия 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-файлов в независимом от кодирования образом должно быть более элегантным, но, по крайней мере, я ухожу только с одним открытым файлом.

+0

Может ли перехват [XmlReaderCreate (Stream)] (http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.create.aspx) работать одинаково с точки зрения обнаружения кодирование? –

+0

@petrk. - Я использую XmlTextReader явно, так как это класс, предоставляющий свойство «Кодирование». Не знаете, что еще вы имели в виду? –

+0

Право, позвольте мне объяснить. Кажется, что 'XElement.Load (XmlReader.Create (новый FileStream (путь к файлу, FileMode.Open)))' должен сделать кое-что (распоряжение ресурсами опущено для краткости). В документации для [XmlReader.Create (Stream)] (http://msdn.microsoft.com/en-us/library/756wd7zs.aspx) говорится: _The XmlReader сканирует первые байты потока, ищущие отметку порядка байтов или другой признак кодирования. Когда кодирование определено, кодирование используется для продолжения чтения потока, и обработка продолжает анализировать входные данные как поток символов (Unicode). Мне было интересно, не отличается ли ваше явное определение кодировки –

0

Другой вариант, довольно простой, - использовать Linq для 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); 

Хотя это может не сервер оригинального плаката, так как ему придется реорганизовать много кода, это полезно для тех, кто должен написать новый код для своего проекта, или если они считают, что рефакторинг стоит того.