2009-05-18 10 views
6

XML文書は非常に大きく(約120M)、すぐにメモリにロードしたくありません。私の目的は、このファイルが有効なUTF-8エンコーディングを使用しているかどうかを確認することです。UTF-8を使用してファイルストリームをデコードする

byte[]の形式でファイル全体をメモリに読み込まずにすばやくチェックするアイデアはありますか?

私はVSTS 2008とC#を使用しています。

無効なバイトシーケンスが含まれているXMLドキュメントをロードするのにXMLDocumentを使用すると、例外がありますが、すべてのコンテンツをバイト配列に読み込んだ後、UTF-8をチェックすると例外はありません。ここで

は私のXMLファイルの内容を示すスクリーンショットである、またはあなたが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:new UTF8Encoding(true, true)を使用している場合は例外がありますが、new UTF8Encoding(false, true)を使用している場合はexスローされるception。例外がスローされるかどうかを制御する2番目のパラメータ(無効なバイトシーケンスがある場合)、なぜ1番目のパラメータが重要なのか、混乱していますか? George2 @

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

ランダムなバイト値であっても、有効なUTF8でさえ、ほとんどのバイトシーケンスではありませんか?または、有効なUTF8でないバイト値シーケンスがありますか? – ChrisW

+1

それらのすべてではなく、いくつかの例外があります。 http://en.wikipedia.org/wiki/UTF-8#Invalid_code_points – George2

+1

@ChrisW:絶対にそうではありません。 UTF-8には特定のエンコード規則があります。 –

答えて

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

しかし、複数のバイトを使用するキャラクターがチャンクにまたがる場合、どのようにそのような状況に対処しますか? – George2

+1

@ George - 読者はデコードされたチャンクを配信します。ストリーム全体がデコードされた場合は有効です。 * chars *のチャンクにまたがるエンコードされた* bytes *の質問はありません。 –

+0

@ソフトウェアモンキー、私はあなたが "読者が提供する"ということを混乱させています - あなたのコードスニペットを表示できますか? – George2

3

私は、彼らが(私がテストしていない)、次のようなソリューションを意味すると思います。

バッファ間の遷移の処理(つまり、読み込み間の余分なバイト/部分文字のキャッシュ)は、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、小さなバグ、Read(buffer、bufferSize、0)はRead(buffer、0、bufferSize)にする必要があります。 :-) 別の問題は、あなたのメソッドを見つけて、XMLDocument.Loadを使用すると結果が異なることです。あなたのメソッドは、基礎となるファイル(例えばTestFile.txt)にUTF-8の無効なバイト列があっても例外をスローしませんが、XMLDocument.Loadは例外をスローします。オリジナルの投稿のEDIT1セクションを参照してください。どんなアイデアが間違っている? – George2

+1

私はわかりません(私は、以下の提案を行うためのコード例を与えていました)。あなたはどんな例外を捕まえていますか?ファイル内のUTF8が正しいかどうかを(独立して)知っていますか?それが間違っていると思われ、上のコードが失敗していない場合は、Visual Studioでコードを実行して、処理されていないときだけ例外をスローします。たぶん(理由は分かりませんが)StreamReaderの実装は、エンコーディングの例外を静かにキャッチします。 – ChrisW

+0

@ChrisW、私のXMLファイルはシンプルで小さく、コンテンツは、 http://i42.tinypic.com/wioc9c.jpg XMLDocumentを使用する場合です。ロードすると、xmlファイルは無効なUTF-8エンコーディングとして扱われますが、メソッドを使用すると、有効なエンコーディングとして扱われます。 – George2

0

これは機能しませんか?

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

誰かが理由を説明できない場合は、

関連する問題