2009-05-18 10 views
6

J'ai un document XML, ce qui est très grand (environ 120 millions), et je ne veux pas le charger dans la mémoire à la fois. Mon but est de vérifier si ce fichier utilise un codage UTF-8 valide.décoder un flux de fichiers en utilisant UTF-8

Toutes les idées pour avoir un contrôle rapide sans lire le fichier entier en mémoire sous forme de byte[]? J'utilise VSTS 2008 et C#. Lorsque vous utilisez XMLDocument pour charger un document XML contenant des séquences d'octets non valides, il existe une exception, mais lorsque vous lisez tout le contenu dans un tableau d'octets et que vous vérifiez par rapport à UTF-8, aucune exception, aucune idée?

Voici une capture d'écran montrant le contenu de mon fichier XML, ou vous pouvez télécharger une copie du fichier 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; 
    } 
} 

EDIT 2: Lors de l'utilisation new UTF8Encoding(true, true) il y aura une exception, mais lors de l'utilisation new UTF8Encoding(false, true), il n'y a pas ex Ception jeté. Je suis confus, car il devrait être le 2ème paramètre qui contrôle si une exception est levée (s'il y a des séquences d'octets invalides), pourquoi le 1er paramètre est-il important?

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

Est-ce que presque aucune séquence d'octets, même des valeurs d'octets aléatoires, n'est valide pour l'UTF8? Ou existe-t-il des séquences de valeurs d'octets qui ne sont pas valides UTF8? – ChrisW

+1

Pas tous, il y a quelques exceptions, s'il vous plaît se référer ici, http://en.wikipedia.org/wiki/UTF-8#Invalid_code_points – George2

+1

@ChrisW: Absolument pas; UTF-8 a des règles de codage spécifiques. –

Répondre

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

Mais si un caractère utilisant plusieurs octets s'étend sur des morceaux, comment gérez-vous cette situation? – George2

+1

@George - le lecteur va livrer des morceaux * décodés *, que vous venez de jeter. Si le flux entier décode, c'est valide. Aucune question de * octets * codés couvrant les morceaux de * caractères * que vous avez lus. –

+0

@Software Monkey, je suis confus au sujet de ce que vous voulez dire "le lecteur livrera" - pourriez-vous montrer votre extrait de code s'il vous plaît? – George2

3

@ George2 Je pense qu'ils veulent dire une solution comme ce qui suit (que je ne l'ai pas testé).

La gestion de la transition entre les tampons (c'est-à-dire la mise en cache d'octets supplémentaires/caractères partiels entre les lectures) est la responsabilité et un détail d'implémentation interne de l'implémentation 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 petit bogue, Read (buffer, bufferSize, 0), devrait être Read (buffer, 0, bufferSize). :-) Un autre problème est, je trouve votre méthode et en utilisant XMLDocument.Load aura des résultats différents. Votre méthode ne lèvera jamais d'exception même s'il existe des séquences d'octets invalides de UTF-8 dans le fichier sous-jacent (par exemple TestFile.txt), mais XMLDocument.Load lèvera une exception. Veuillez vous référer à la section EDIT1 de mon article original. Des idées ce qui ne va pas? – George2

+1

Je ne sais pas (je donnais seulement un exemple de code pour perroquet les suggestions ci-dessous). Quelle exception attrapez-vous? Savez-vous (indépendamment) si UTF8 dans le fichier est correct ou non? Si vous êtes sûr que c'est incorrect, et que le code ci-dessus n'échoue pas, essayez d'exécuter le code avec Visual Studio pour attraper les exceptions quand elles sont lancées, et non seulement quand elles ne sont pas gérées? Parce que peut-être (bien que je ne saurais pas pourquoi) l'implémentation StreamReader attrape silencieusement toutes les exceptions de codage. – ChrisW

+0

@ChrisW, mon fichier XML est simple et petit, le contenu est, http://i42.tinypic.com/wioc9c.jpg lors de l'utilisation de XMLDocument.Charger, le fichier xml sera traité comme un codage UTF-8 non valide, mais lors de l'utilisation de votre méthode, il sera traité comme un encodage valide - aucune exception, aucune idée? – George2

0

Cela ne fonctionnerait-il pas?

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 non, quelqu'un peut-il vous expliquer pourquoi?

Questions connexes