【问题标题】:Reading\Writing Structured Binary File读\写结构化二进制文件
【发布时间】:2011-11-04 17:37:22
【问题描述】:

我想读\写一个具有以下结构的二进制文件:

文件由“记录”组成。每个“记录”具有以下结构: 我将以第一条记录为例

  • (红色)起始字节:0x5A(始终为 1 字节,固定值 0x5A)
  • (绿色)LENGTH 个字节:0x00 0x16(始终为 2 个字节,值可以从 “0x00 0x02”到“0xFF 0xFF”)
  • (蓝色) CONTENT:由 LENGTH 字段的十进制值减去 2 表示的字节数。在这种情况下,LENGHT 字段的值为 22(0x00 0x16 转换为十进制),因此 CONTENT 将包含 20 (22 - 2) 个字节.

我的目标是逐条读取每条记录,并将其写入输出文件。 其实我有一个读函数和写函数(一些伪代码):

private void Read(BinaryReader binaryReader, BinaryWriter binaryWriter)
{
    byte START = 0x5A;
    int decimalLenght = 0;
    byte[] content = null;
    byte[] length = new byte[2];

    while (binaryReader.PeekChar() != -1)
    {
        //Check the first byte which should be equals to 0x5A
        if (binaryReader.ReadByte() != START)
        {
            throw new Exception("0x5A Expected");
        }

        //Extract the length field value
        length = binaryReader.ReadBytes(2);

        //Convert the length field to decimal
        int decimalLenght = GetLength(length);

        //Extract the content field value
        content = binaryReader.ReadBytes(decimalLenght - 2);

        //DO WORK
        //modifying the content

        //Writing the record
        Write(binaryWriter, content, length, START);
    }
}

private void Write(BinaryWriter binaryWriter, byte[] content, byte[] length, byte START)
{
    binaryWriter.Write(START);
    binaryWriter.Write(length);
    binaryWriter.Write(content);   
}

这种方式确实有效。 但是,由于我正在处理非常大的文件,我发现它根本没有执行,因为我对每个记录进行了 3 次读写。实际上,我想读取错误的数据块而不是少量字节,并且可能在内存中工作,但是我在使用 Stream 方面的经验停止使用 BinaryReader 和 BinaryWriter。提前致谢。

【问题讨论】:

    标签: c# .net bytebuffer afp


    【解决方案1】:

    FileStream 已经被缓冲了,所以我希望它能很好地工作。如果确实需要,您始终可以在原始流周围创建一个 BufferedStream 以添加额外的缓冲,但我怀疑它会产生显着差异。

    你说它“根本没有表现”——它的工作速度有多快?您有多确定 IO 是您的时间去向?您是否对代码进行了任何分析?

    【讨论】:

    • FileStream 有一个控制缓冲区大小的构造函数参数。要考虑的另一件事是操作系统本身也有缓冲。
    • @JamesJohnston:确实。我希望默认值在大多数情况下都很好。我怀疑这真的是问题所在。
    • 我同意。我确实遇到了一个例外,尽管不是 C#。我使用的 C 运行时默认为 512 字节缓冲区。因此,当一次读取 4 个字节的数据文件时(我们的程序就是这样做的),磁盘性能会非常慢。当然,这通常不是问题,因为即使程序没有完成足够的工作,操作系统也会缓冲读取。
    • 然而,网络驱动器呈现出一种特殊情况。预读可能很危险:另一个客户端可以写入,从而使客户端的缓冲区无效。 Windows 使用机会锁定 (oplocks) 仍然可以安全地通过网络进行预读缓冲。长话短说,如果网络连接丢失,一些传统的基于文件的系统(Paradox/MS Access/QuickBooks/等)可能会遇到严重的文件损坏。这些人可能会禁用 oplocks 以保持数据库完整性。发生这种情况时,我们的读取性能下降了,因为只使用了 C 运行时 512 字节缓冲区。
    • 但是,如果 OP 没有在禁用 oplocks 的网络驱动器上工作,那么问题很可能出在其他地方,并且 OP 可能需要更多地分析代码。
    【解决方案2】:

    我还可能建议您最初读取 3 个(或 6 个?)字节,而不是 2 个单独的读取。将初始字节放入一个小数组中,检查 5a ck-byte,然后是 2 字节长度指示符,然后是 3 字节 AFP 操作码,然后,读取 AFP 记录的其余部分。

    这是一个很小的区别,但它消除了您的一个读取调用。

    我不是 Jon Skeet,但我确实在该国最大的印刷和邮件商店之一工作了很长一段时间,我们主要做 AFP 输出 :-)

    (不过通常在 C 中)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多