2009-05-18 15 views
6

Mam dokument XML, który jest bardzo duży (około 120M) i nie chcę go załadować do pamięci naraz. Moim celem jest sprawdzenie, czy ten plik używa prawidłowego kodowania UTF-8.dekodowanie strumienia plików przy użyciu UTF-8

Wszelkie pomysły na szybką kontrolę bez czytania całego pliku do pamięci w postaci byte[]?

Używam VSTS 2008 i C#.

Podczas ładowania dokumentu XML, który zawiera niepoprawne sekwencje bajtów, istnieje wyjątek, ale podczas odczytywania całej zawartości do tablicy bajtów, a następnie sprawdzania z UTF-8, nie ma wyjątków, żadnych pomysłów?

Oto zrzut ekranu pokazujący zawartość mojego pliku XML, czy można pobrać kopię pliku z 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: Podczas korzystania z new UTF8Encoding(true, true) pojawi się wyjątek, ale podczas korzystania z new UTF8Encoding(false, true), nie ma rzucony cepel. Jestem zdezorientowany, ponieważ powinien to być drugi parametr, który kontroluje, czy wyjątek jest zgłaszany (jeśli występują niepoprawne sekwencje bajtów), dlaczego pierwszy parametr ma znaczenie?

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

Nie jest prawie żadna sekwencja bajtów, nawet losowe wartości bajtów, poprawne UTF8? Czy są jakieś sekwencje wartości bajtów, które nie są poprawne w UTF8? – ChrisW

+1

Nie wszystkie z nich, są pewne wyjątki, proszę zapoznać się tutaj, http://pl.wikipedia.org/wiki/UTF-8#Numer_zastosowania – George2

+1

@ChrisW: Absolutnie nie; UTF-8 ma określone reguły kodowania. –

Odpowiedz

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

Ale jeśli postać używająca wielu bajtowych fragmentów, jak sobie z tym poradzisz? – George2

+1

@George - czytnik dostarczy * dekodowane * kawałki, które po prostu wyrzucisz. Jeśli cały strumień zostanie odkodowany, jest ważny. Bez pytania o zakodowane * bajty * obejmujące fragmenty * znaków *, które czytasz. –

+0

@Software Monkey, jestem zdezorientowany tym, co masz na myśli "czytelnik dostarczy" - czy możesz pokazać swój fragment kodu? – George2

3

@ George2 myślę znaczy, że rozwiązanie jak poniżej (które nie zostały przetestowane).

Obsługa przejścia między buforami (np. Buforowanie dodatkowych bajtów/znaków częściowych między odczytami) jest odpowiedzialnością i wewnętrznym szczegółem implementacji implementacji 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, mały błąd, Read (buffer, bufferSize, 0), powinien być Read (buffer, 0, bufferSize). :-) Inną kwestią jest, że znajdę twoją metodę i używając XMLDocument.Load będzie miał różne wyniki. Twoja metoda nigdy nie wyrzuci żadnego wyjątku, nawet jeśli występują nieważne sekwencje UTF-8 w pliku bazowym (np. TestFile.txt), ale XMLDocument.Load zwróci wyjątek. Zapoznaj się z częścią EDIT1 mojego oryginalnego wpisu. Jakieś pomysły, co jest nie tak? – George2

+1

Nie wiem (podałem tylko przykład kodu, aby zasugerować poniższe sugestie). Jaki wyjątek łapiesz? Czy znasz (niezależnie), czy kodowanie UTF8 w pliku jest poprawne? Jeśli jesteś pewien, że jest niepoprawny, a powyższy kod się nie kończy, spróbuj uruchomić kod za pomocą zestawu Visual Studio, aby wychwycić wyjątki, gdy są one zgłaszane, a nie tylko wtedy, gdy są nieobsługiwane? Bo może (choć nie wiem dlaczego) implementacja StreamReadera po cichu przechwytuje wszystkie wyjątki kodowania. – ChrisW

+0

@ ChhrisW, mój plik XML jest prosty i mały, treść jest, http://i42.tinypic.com/wioc9c.jpg podczas korzystania z XMLDocument.Załaduj, plik xml będzie traktowany jako nieprawidłowe kodowanie UTF-8, ale używając tej metody będzie traktowany jako prawidłowe kodowanie - bez wyjątków, żadnych pomysłów? – George2

0

Czy to nie zadział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(); 

Jeśli nie, ktoś może pomóc ci wyjaśnić dlaczego?

Powiązane problemy