8

我需要能够以自定义二进制文件格式存储一些数据。我以前从未设计过自己的文件格式。它需要是一种在 C#、Java 和 Ruby/Perl/Python 世界之间穿梭的友好格式。

首先文件将包含记录。一个 GUID 字段和一个 JSON/YAML/XML 数据包字段。我不确定用什么作为分隔符。逗号、制表符或换行符之类的东西似乎太脆弱了。Excel 是做什么的?还是 XML 之前的 OpenOffice 格式?您应该使用 ASCII 字符 0 还是 1。不知道从哪里开始。有没有关于这个主题的文章或书籍?

此文件格式稍后可能会扩展为包含“标题部分”。

注意:首先我将在 .NET 中工作,但我希望该格式易于移植。

更新:
“数据包”的处理可能很慢,但文件格式内的导航不能。所以我认为 XML 不在讨论范围内。

4

5 回答 5

7

看看使用“协议缓冲区”怎么样?设计为一种高效、可移植、版本兼容的通用二进制格式,它为您提供谷歌库中的 C++、Java 和 Python,以及社区端口中的 C#、Perl、Ruby 和其他?

请注意, Guid 没有特定的数据类型,但您可以使用(基本上) a 将其作为消息填充byte[]

通常对于 .NET 工作,我会推荐protobuf-net (但作为作者,我有些偏见) - 但是,如果您打算稍后使用其他语言,则使用 Jon 的dotnet-protobufs可能会做得更好(长期);这将为您提供跨平台的熟悉 API(其中 protobuf-net 使用 .NET 习语)。

于 2009-04-27T19:49:28.430 回答
3

ASCII 字符 0 或 1 每个占用几个位(就像任何其他字符一样),所以如果你这样存储它,你的“二进制”文件将比​​它应该的大几倍。在零和一的文本文件不完全是二进制文件:)

您可以使用BinaryWriter将原始数据直接写入文件流。您需要弄清楚的唯一部分是将您的内存格式(通常是某种对象图)转换为 BinaryWriter 可以使用的字节序列。

但是,如果您的主要兴趣是可移植性,我建议您完全反对二进制格式。XML 正是为解决可移植性和互操作性问题而设计的。作为一种文件格式,它既冗长又繁重,但这是您为解决这些问题所做的权衡。如果人类可读的格式不在桌面上,Marc 的答案就是要走的路。无需重新发明便携轮!

于 2009-04-27T19:44:52.233 回答
3

我将尝试添加一些用于创建可移植二进制文件格式的一般提示。

请注意,发明二进制文件格式意味着记录其中的位必须如何传输以及它们的含义。它不是编码,而是文档。

现在提示:

  1. 决定如何处理字节序。好的和简单的方法是一劳永逸地决定它。在普通 PC(即 x86)上使用时,选择最好是小端,以节省转换(性能)。

  2. 创建标题。是的,总是有一个标题是个好主意。文件的第一个字节应该能够告诉你,你在搞乱什么格式。

    • 从能够识别您的格式的魔法开始(ASCII 字符串就可以了)
    • 添加版本。添加文件格式的版本不会有什么坏处,它可以让您稍后进行向后兼容。
  3. 最后,添加数据。现在,数据的格式将是特定的,它将始终基于您的确切需求。基本上,数据将存储在某种数据结构的二进制映像中。数据结构是您需要提出的。

如果您需要通过某种索引随机访问您的数据,B-Trees是一种选择,而如果您只需要大量的数字来将它们全部写入然后读取它们,那么“数组”就可以解决问题。

此外,您可以使用TLV(类型-长度-值)概念来实现前向兼容性。

于 2015-04-29T14:06:12.270 回答
1

这取决于您将写入二进制文件的数据类型以及二进制文件的用途。它们是类对象还是只是记录数据?如果是记录数据,我建议将其放入 xml 格式。这样,您可以包含模式验证以验证文件是否符合您的标准。java 和 .NET 中都有工具可以从 / 到 xml 格式导入和导出数据。

于 2009-04-27T19:53:09.980 回答
1

假设您的格式是:

    struct Format
    {
        struct Header // 1
        {
            byte a;
            bool b1, b2, b3, b4, b5, b6, b7, b8;
            string name;
        }
        struct Container // 1...*
        {
            MyTypeEnum Type;
            byte[] data;
        }
    }

    enum MyTypeEnum
    {
        Sound,
        Video,
        Image
    }

然后我会有一个顺序文件:


字节 // 一个

字节 // b

int // 名称大小

char[] // 名称(具有上面指定的大小,记住 .NET 中的 char 是 16 位)

int // MyTypeEnum 类型

int // 数据大小

byte[] // 数据(具有上面指定的大小)


然后,您可以根据需要重复最后三行。

要阅读,请使用BinaryReader它支持读取字节、整数和字节序列。还有一个BinaryWriter

此外,请记住 Microsoft .NET(因此在 Windows/Intel 机器上)是 little-endian。BinaryReader和也是如此BinaryWriter

于 2009-04-27T21:05:21.993 回答