使用Stream.Read()和BinaryReader.Read()来处理二进制流

w12*_*128 19 .net c# stream

当使用二进制流(即byte[]数组)时,使用BinaryReaderBinaryWriter似乎是简化从流中读取/写入原始数据类型的主要观点,使用诸如ReadBoolean()考虑编码的方法.这是整个故事吗?如果直接使用a Stream而不使用BinaryReader/BinaryWriter?是否存在固有的优势或劣势?大多数方法,例如Read(),在两个类中似乎都是相同的,我的猜测是它们在下面工作相同.

考虑一个以两种不同方式处理二进制文件的简单示例(编辑:我意识到这种方式是无效的,可以使用缓冲区,它只是一个示例):

// 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出将是相同的,但内部发生了什么(例如从OS的角度来看)?是 - 一般来说 - 重要的是使用哪种实现?BinaryReader/BinaryWriter如果您不需要他们提供的额外方法,是否有任何使用目的?对于这个特定情况,MSDN在以下方面说Stream.ReadByte():

Stream上的默认实现创建一个新的单字节数组,然后调用Read.虽然这是正式的,但效率低下.

使用时GC.GetTotalMemory(),第一种方法似乎分配的空间是第二种方法的2倍,但如果使用更通用的Stream.Read()方法(例如,使用缓冲区读取块),AFAIK就不应该这样.不过,在我看来,这些方法/接口可以轻松统一......

Hen*_*man 14

不,这两种方法之间没有本质区别.额外的Reader增加了一些缓冲,所以你不应该混合它们.但不要指望任何显着的性能差异,它都由实际的I/O支配.

所以,

  • 当你(仅)byte[]移动时使用流.在许多流媒体场景中很常见.
  • 当您要处理任何其他基本类型(包括简单byte)数据时,请使用BinaryWriter和BinaryReader .它们的主要目的是将内置框架类型转换为byte[].


poy*_*poy 11

一个很大的区别是如何缓冲I/O. 如果你在这里或那里只写几个字节,那么效果BinaryWriter/BinaryReader会很好.但是,如果你要读数据的MBS,然后读一个byte,Int32等...在同一时间将是一个有点慢.你可以改为阅读更大的块并从那里解析.

例:

// 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]));
}
Run Code Online (Sandbox Code Playgroud)

现在这有点偏离主题......但我会把它扔出去:如果你想得到非常狡猾......并且真的给自己一个性能提升......(虽然,它可能被认为是危险的)而不是解析EACH Int32,你可以一次性使用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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

关于这个例子需要注意的几点:这个每个Int32需要4个字节而不是一个...所以它会产生不同的结果.您也可以为Int32以外的其他数据类型执行此操作,但许多人会认为编组应该在您的脑海中.(我只是想提出一些值得考虑的事情......)