2009-05-18 7 views
6

Tengo un documento XML, que es muy grande (aproximadamente 120M), y no quiero cargarlo en la memoria de una vez. Mi propósito es verificar si este archivo está usando codificación UTF-8 válida.decodificar una secuencia de archivos usando UTF-8

¿Alguna idea de tener una comprobación rápida sin leer todo el archivo en la memoria en forma de byte[]?

Estoy usando VSTS 2008 y C#.

Al utilizar XMLDocument para cargar un documento XML, que contiene secuencias de bytes no válidas, existe una excepción, pero cuando lee todo el contenido en una matriz de bytes y luego compara con UTF-8, ¿hay alguna idea?

Aquí es una captura de pantalla que muestra el contenido de mi archivo XML, o se puede descargar una copia del archivo de here

enter image description here

EDIT 1:

class Program 
{ 
    public static byte[] RawReadingTest(string fileName) 
    { 
     byte[] buff = null; 

     try 
     { 
      FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); 
      BinaryReader br = new BinaryReader(fs); 
      long numBytes = new FileInfo(fileName).Length; 
      buff = br.ReadBytes((int)numBytes); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 

     return buff; 
    } 

    static void XMLTest() 
    { 
     try 
     { 
      XmlDocument xDoc = new XmlDocument(); 
      xDoc.Load("c:\\abc.xml"); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
    } 

    static void Main() 
    { 
     try 
     { 
      XMLTest(); 
      Encoding ae = Encoding.GetEncoding("utf-8"); 
      string filename = "c:\\abc.xml"; 
      ae.GetString(RawReadingTest(filename)); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 

     return; 
    } 
} 

EDITAR 2: Al usar new UTF8Encoding(true, true) habrá una excepción, pero cuando usa new UTF8Encoding(false, true), no hay ningún ex ception lanzado. Estoy confundido, porque debería ser el segundo parámetro que controla si se lanza una excepción (si hay secuencias de bytes inválidas), ¿por qué importa el primer parámetro?

public static void TestTextReader2() 
    { 
     try 
     { 
      // Create an instance of StreamReader to read from a file. 
      // The using statement also closes the StreamReader. 
      using (StreamReader sr = new StreamReader(
       "c:\\a.xml", 
       new UTF8Encoding(true, true) 
       )) 
      { 
       int bufferSize = 10 * 1024 * 1024; //could be anything 
       char[] buffer = new char[bufferSize]; 
       // Read from the file until the end of the file is reached. 
       int actualsize = sr.Read(buffer, 0, bufferSize); 
       while (actualsize > 0) 
       { 
        actualsize = sr.Read(buffer, 0, bufferSize); 
       } 
      } 
     } 
     catch (Exception e) 
     { 
      // Let the user know what went wrong. 
      Console.WriteLine("The file could not be read:"); 
      Console.WriteLine(e.Message); 
     } 

    } 
+0

¿No hay casi ninguna secuencia de bytes, incluso valores de bytes aleatorios, UTF8 válido? ¿O hay algunas secuencias de valores de bytes que no son válidas UTF8? – ChrisW

+1

No todos, hay algunas excepciones, consulte aquí, http://en.wikipedia.org/wiki/UTF-8#Invalid_code_points – George2

+1

@ChrisW: Absolutamente no; UTF-8 tiene reglas de codificación específicas. –

Respuesta

5
var buffer = new char[32768] ; 

using (var stream = new StreamReader (pathToFile, 
    new UTF8Encoding (true, true))) 
{ 
    while (true) 
    try 
    { 
     if (stream.Read (buffer, 0, buffer.Length) == 0) 
      return GoodUTF8File ; 
    } 
    catch (ArgumentException) 
    { 
     return BadUTF8File ; 
    } 
} 
+0

Pero si un personaje que usa múltiples bytes abarca segmentos, ¿cómo maneja esa situación? – George2

+1

@George - el lector entregará * fragmentos decodificados *, que usted acaba de descartar. Si la secuencia completa se decodifica, era válida. No hay dudas sobre los * bytes * codificados que abarcan los trozos de * caracteres * que lees. –

+0

@Software Monkey, estoy confundido acerca de a qué te refieres con "el lector entregará". ¿Podrías mostrar tu fragmento de código por favor? – George2

3

@ George2 creo que significan una solución como la siguiente (que no he probado).

La gestión de la transición entre almacenamientos intermedios (es decir, caché de bytes adicionales/caracteres parciales entre lecturas) es la responsabilidad y un detalle de la implementación interna de la implementación de StreamReader.

using System; 
using System.IO; 
using System.Text; 

class Test 
{ 
    public static void Main() 
    { 
     try 
     { 
      // Create an instance of StreamReader to read from a file. 
      // The using statement also closes the StreamReader. 
      using (StreamReader sr = new StreamReader(
       "TestFile.txt", 
       Encoding.UTF8 
       )) 
      { 
       const int bufferSize = 1000; //could be anything 
       char[] buffer = new char[bufferSize]; 
       // Read from the file until the end of the file is reached. 
       while (bufferSize == sr.Read(buffer, bufferSize, 0)) 
       { 
        //successfuly decoded another buffer's-worth of data 
       } 
      } 
     } 
     catch (Exception e) 
     { 
      // Let the user know what went wrong. 
      Console.WriteLine("The file could not be read:"); 
      Console.WriteLine(e.Message); 
     } 
    } 
} 
+0

@ChrisW, un pequeño error, Read (buffer, bufferSize, 0), debe ser Read (buffer, 0, bufferSize). :-) Otro problema es que me parece que su método y el uso de XMLDocument.Load tendrán resultados diferentes. Su método nunca lanzará ninguna excepción, incluso si hay secuencias de bytes inválidas de UTF-8 en el archivo subyacente (por ejemplo, TestFile.txt), pero XMLDocument.Load arrojará una excepción. Consulte la sección EDIT1 de mi publicación original. ¿Alguna idea de lo que está mal? – George2

+1

No lo sé (solo estaba dando un ejemplo de código para repetir las sugerencias a continuación). ¿Qué excepción estás atrapando? ¿Sabe (independientemente) si el UTF8 en el archivo es correcto o no? Si está seguro de que es incorrecto y el código anterior no está fallando, intente ejecutar el código con Visual Studio configurado para detectar excepciones cuando se lanzan, en lugar de hacerlo solo cuando no están siendo administradas. Porque tal vez (aunque no sabría por qué) la implementación de StreamReader capta silenciosamente cualquier excepción de Codificación. – ChrisW

+0

@ChrisW, mi archivo XML es simple y pequeño, el contenido es http://i42.tinypic.com/wioc9c.jpg cuando se usa XMLDocument.Cargar, el archivo xml se tratará como una codificación UTF-8 no válida, pero cuando use su método, se tratará como una codificación válida, sin excepciones ni ideas. – George2

0

¿Esto no funcionaría?

StreamReader reader = new StreamReader(file); 

Console.WriteLine(reader.CurrentEncoding.ToString()); //You get the default encoding 
reader.Read(); 

Console.WriteLine(reader.CurrentEncoding.ToString()); //You get the right encoding. 
reader.Close(); 

Si no alguien puede ayudar a explicar por qué?

Cuestiones relacionadas