65.9K
CodeProject 正在变化。 阅读更多。
Home

BinaryIO: 以平台无关的方式轻松读取和写入二进制流

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2020年3月19日

MIT

3分钟阅读

viewsIcon

7853

downloadIcon

172

BinaryReader 和 BinaryWriter 可以更轻松地以可移植的方式解析或写入二进制文件

引言

Microsoft .NET 提供了许多读取器和写入器类,用于读取和写入文本数据,但没有提供除 Stream 本身之外的任何东西来读取或写入二进制数据。 当然,他们提供了 BitConverter,但它的平台中立性不高,并且不管理游标。 本文和随附的代码旨在填补 .NET 框架中的这一空白。

更新: 现在支持 floatdouble

更新 2: 添加了 BinaryWriter, 更改了库名称

概念化这个混乱的局面

通常,在从二进制文件读取或写入到二进制文件时,您经常处理数字值,这些数字值可能具有多个字节的长度,并且以与您运行的机器期望的方式不同的方式进行编码。 您经常会遇到必须重新排序构成 worddwordqwordfloatdouble 的字节的情况。 此类使以任何字节顺序读取和写入数字值到流或从流中读取和写入非常容易。 我们可以使用 BinaryReader 类及其派生类 BinaryStreamReaderBinaryCollectionReader 以我们需要的任何字节顺序读取值。 同样,我们可以使用 BinaryWriter 及其派生类 BinaryStreamWriterBinaryCollectionWriter 分别写入 Stream 或字节集合。

编写这个混乱的程序

包括一个小演示,它只是从包含的 MIDI 文件中读取一些值,我从那些铃声 MIDI 站点之一下载了该文件

// open the MIDI file
using(var br = new BinaryStreamReader(@"..\..\GORILLAZ_-_Feel_Good_Inc.mid"))
{
    // check for the FourCC code at the beginning of the file
    if("MThd"!=br.ReadFixedString(4,Encoding.ASCII))
        throw new ApplicationException("The file is not a MIDI file");
                
    // read a big-endian 32-bit integer length from the file
    var len = br.ReadInt32BE();
    // now read that many bytes into a buffer
    var ba = br.ReadBytes(len);
    // create a new binary reader over ba
    // not necessary, but for illustrative purposes:
    using (var br2 = new BinaryCollectionReader(ba))
    {
        // read the file type as a big-endian 16-bit short
        Console.WriteLine("MIDI File Type: " + br2.ReadInt16BE().ToString());
        // read the track count as a big-endian 16-bit short
        Console.WriteLine("MIDI Track Count: " + br2.ReadInt16BE().ToString());
        // read the timebase as a big-endian 16-bit short
        Console.WriteLine("MIDI TimeBase: " + br2.ReadInt16BE().ToString());
    }
}

希望这些注释能够阐明它正在做什么。 MIDI 文件以大端格式存储,而 Intel 机器是小端格式。 因此,我们使用 ReadXXXXBE() - 注意 BE 后缀 - 读取大端值。 以 LE 结尾的读取方法则读取小端形式的内容,而没有后缀的 ReadXXXX() 以您平台的本机字节顺序读取值。 使用正确的方法将确保根据需要将该值转换为适合您平台的字节顺序。 上面需要注意的一件事是在字节数组上创建了一个额外的读取器。 正如注释所说,不必以这种方式实现它,但它说明了一种技术,即它使用嵌套读取器来安全地读取块或子流值。 这在文件被分成不同的块或子流的情况下很有用,就像 MIDI 文件一样。 但是,正如我所说,上面太简单了,我们实际上不需要这样做。

我没有在演示中涵盖写入,因为编写 MIDI 文件会使演示项目更加复杂。 写入与读取相反,并且 API 彼此是镜像,因此应该很容易解决。 所有内容都有文档记录。

该库可以使用大量额外的读取和写入方法,例如 decimal、以零结尾的 string 等的读取和写入方法。 我将其作为读者的练习。

历史

  • 2020 年 3 月 19 日 - 首次提交
  • 2020 年 3 月 19 日 - 更新以支持 float 和 double 值
  • 2020 年 3 月 19 日 - 更新以添加 BinaryWriter 及其派生类。 更改了库的名称
© . All rights reserved.