24

バイナリ ストリーム (つまりbyte[]、配列) を操作するBinaryReader場合、 orを使用する主なポイントは、 やBinaryWriterなどの方法を使用してストリームからプリミティブ データ型を簡単に読み書きできるように思わReadBoolean()れます。エンコーディングを考慮します。それが全体の話ですか?Streamを使用せずに を直接操作する場合、固有の利点または欠点はありBinaryReader/BinaryWriterますか? などのほとんどのメソッドはRead()、両方のクラスで同じように見えます。私の推測では、それらは下で同じように機能します。

バイナリ ファイルを 2 つの異なる方法で処理する簡単な例を考えてみましょう (編集: この方法は効果がなく、バッファーを使用できることを認識しています。これは単なるサンプルです)。

// Using FileStream directly
using (FileStream stream = new FileStream("file.dat", FileMode.Open))
{
    // Read bytes from stream and interpret them as ints
    int value = 0;
    while ((value = stream.ReadByte()) != -1)
    {
        Console.WriteLine(value);
    }
}


// Using BinaryReader
using (BinaryReader reader = new BinaryReader(FileStream fs = new FileStream("file.dat", FileMode.Open)))
{
    // Read bytes and interpret them as ints
    byte value = 0;    
    while (reader.BaseStream.Position < reader.BaseStream.Length)
    {
        value = reader.ReadByte();
        Console.WriteLine(Convert.ToInt32(value));
    }
}

出力は同じですが、内部で何が起こっているのでしょうか (たとえば、OS の観点から)? 一般的に言えば、どの実装が使用されているかが重要ですか? BinaryReader/BinaryWriterそれらが提供する追加のメソッドが必要ない場合、使用する目的はありますか? この特定のケースについて、MSDN は に関して次のように述べていStream.ReadByte()ます。

Stream の既定の実装では、新しいシングルバイト配列を作成してから、Read を呼び出します。これは正式には正しいですが、非効率的です。

を使用するGC.GetTotalMemory()と、この最初のアプローチは2番目のアプローチの2倍のスペースを割り当てるように見えますが、より一般的なStream.Read()方法が使用されている場合(たとえば、バッファを使用してチャンクを読み取る場合)、これは当てはまりません。それでも、これらのメソッド/インターフェースは簡単に統合できるように思えます...

4

3 に答える 3

18

いいえ、2 つのアプローチに主な違いはありません。余分なリーダーはバッファリングを追加するため、それらを混在させないでください。ただし、大きなパフォーマンスの違いは期待しないでください。実際の I/O がすべてを支配しています。

そう、

  • 移動する必要がある場合 (のみ) にストリームを使用しますbyte[]。多くのストリーミング シナリオでよくあることです。
  • 処理する他の基本型 ( simple を含むbyte) のデータがある場合は、 BinaryWriter と BinaryReader を使用します。それらの主な目的は、組み込みのフレームワーク タイプを に変換することbyte[]です。
于 2013-06-11T12:12:28.607 に答える
13

大きな違いの 1 つは、I/O をバッファリングする方法です。あちこちに数バイトだけ書き込み/読み取りを行っている場合は、BinaryWriter/BinaryReaderうまく機能します。しかし、MB 単位のデータを読み取る必要がある場合、一度byteInt32, などを 1 つずつ読み取ると、少し遅くなります。代わりに、より大きなチャンクを読み取り、そこから解析することができます。

例:

// Using FileStream directly with a buffer
using (FileStream stream = new FileStream("file.dat", FileMode.Open))
{
    // Read bytes from stream and interpret them as ints
    byte[] buffer = new byte[1024];
    int count;
    // Read from the IO stream fewer times.
    while((count = stream.Read(buffer, 0, buffer.Length)) > 0)
        for(int i=0; i<count; i++)
           Console.WriteLine(Convert.ToInt32(buffer[i]));
}

さて、これは少し話題から外れています... しかし、私はそれを捨てます: もしあなたが非常に狡猾になりたいなら...そして本当に自分自身のパフォーマンスを向上させたいなら... (とはいえ、それは危険と見なされるかもしれません)代わりにEACHInt32を解析すると、一度にすべてを実行できますBuffer.BlockCopy()

もう一つの例:

// Using FileStream directly with a buffer and BlockCopy
using (FileStream stream = new FileStream("file.dat", FileMode.Open))
{
    // Read bytes from stream and interpret them as ints
    byte[] buffer = new byte[1024];
    int[] intArray = new int[buffer.Length >> 2]; // Each int is 4 bytes
    int count;
    // Read from the IO stream fewer times.
    while((count = stream.Read(buffer, 0, buffer.Length)) > 0)
    {
       // Copy the bytes into the memory space of the Int32 array in one big swoop
       Buffer.BlockCopy(buffer, 0, intArray, count);

       for(int i=0; i<count; i+=4)
          Console.WriteLine(intArray[i]);
    }
}

この例について注意すべき点がいくつかあります。これは、Int32 ごとに 1 バイトではなく 4 バイトを使用するため、異なる結果が得られます。Int32 以外のデータ型に対してもこれを行うことができますが、多くの人はマーシャリングを念頭に置いておく必要があると主張します。(ちょっと気になることを紹介したかったのですが…)

于 2013-06-11T13:35:58.127 に答える