2009-05-18 12 views
6

Ho un documento XML, che è molto grande (circa 120m), e io non voglio caricarlo in memoria in una sola volta. Il mio scopo è verificare se questo file utilizza la codifica UTF-8 valida.decodificare un flusso di file utilizzando UTF-8

Tutte le idee per avere un rapido controllo senza leggere l'intero file nella memoria in forma di byte[]?

Sto usando VSTS 2008 e C#.

Quando si utilizza XMLDocument per caricare un documento XML che contiene le sequenze di byte non validi, non v'è un'eccezione, ma quando si legge tutti i contenuti in un array di byte e poi controllando contro UTF-8, non esiste alcuna eccezione, tutte le idee?

Ecco uno screenshot che mostra il contenuto del mio file XML, oppure è possibile scaricare una copia del file da 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: Quando si utilizza new UTF8Encoding(true, true) ci sarà un'eccezione, ma quando si utilizza new UTF8Encoding(false, true), non c'è nessun ex getta gettata. Sono confuso, perché dovrebbe essere il 2 ° parametro che controlla se viene lanciata un'eccezione (se ci sono sequenze di byte non valide), perché il 1 ° parametro è importante?

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

non è quasi qualsiasi sequenza di byte, valori anche casuali di byte, UTF8 valida? O ci sono alcune sequenze di valori di byte che non sono UTF8 validi? – ChrisW

+1

Non tutti, ci sono alcune eccezioni, fare riferimento qui, http://en.wikipedia.org/wiki/UTF-8#Invalid_code_points – George2

+1

@ChrisW: Assolutamente no; UTF-8 ha regole di codifica specifiche. –

risposta

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

Ma se un personaggio che utilizza più byte si estende su blocchi, come gestisci tale situazione? – George2

+1

@George - il lettore consegnerà * pezzi decodificati *, che semplicemente scarti. Se l'intero stream decodifica, era valido. Nessuna questione di codificati * byte * che coprono i blocchi di * caratteri * che leggi. –

+0

@Software Monkey, sono confuso su cosa intendi "il lettore consegnerà" - potresti mostrare lo snippet di codice per favore? – George2

3

@ George2 penso significano una soluzione simile alla seguente (che non ho ancora testato).

La gestione della transizione tra i buffer (ovvero il caching di byte aggiuntivi/caratteri parziali tra letture) è la responsabilità e un dettaglio di implementazione interna dell'implementazione 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 piccolo bug, Read (buffer, bufferSize, 0), dovrebbe essere Read (buffer, 0, bufferSize). :-) Un altro problema è che trovo il tuo metodo e l'utilizzo di XMLDocument.Load avrà risultati diversi. Il tuo metodo non genererà mai alcuna eccezione anche se non ci sono sequenze di byte non valide di UTF-8 nel file sottostante (ad esempio TestFile.txt), ma XMLDocument.Load genererà un'eccezione. Si prega di fare riferimento alla sezione EDIT1 del mio post originale. Qualche idea, cosa c'è che non va? – George2

+1

Non so (stavo solo dando un esempio di codice per pappagallo i suggerimenti di seguito). Che eccezione stai prendendo? Sai (indipendentemente) se l'UTF8 nel file è corretto o meno? Se sei sicuro che non sia corretto, e il codice sopra non sta fallendo, prova a eseguire il codice con Visual Studio set per rilevare le eccezioni quando vengono lanciate, invece che solo quando non sono gestite? Perché forse (anche se non saprei perché) l'implementazione StreamReader cattura silenziosamente tutte le eccezioni di codifica. – ChrisW

+0

@ChrisW, il mio file XML è semplice e piccolo, il contenuto è, http://i42.tinypic.com/wioc9c.jpg quando si utilizza XMLDocument.Caricare, il file xml verrà considerato come codifica UTF-8 non valida, ma quando si utilizza il metodo, verrà trattato come codifica valida, senza eccezioni, nessuna idea? – George2

0

Questo non funziona?

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(); 

In caso contrario, qualcuno può spiegare perché?

Problemi correlati