我需要能够以自定义二进制文件格式存储一些数据。我以前从未设计过自己的文件格式。它需要是一个友好的格式,用于在C#,Java和Ruby / Perl / Python世界之间旅行。
首先,文件将包含记录。 GUID字段和JSON / YAML / XML数据包字段。我不确定用什么作为分隔符。逗号,制表符或换行符似乎太脆弱了。 Excel做什么?还是XML前的OpenOffice格式?你应该使用ASCII字符0或1.不知道从哪里开始。有关该主题的任何文章或书籍?
此文件格式可能会稍后扩展,以包含“标题部分”。
注意:首先,我将使用.NET,但我希望该格式易于移植。
更新
“数据包”的处理可能很慢,但文件格式内的导航不能。所以我认为XML已不在考虑之列。
答案 0 :(得分:7)
如何看待使用“协议缓冲区”?设计为高效,可移植,版本容忍的通用二进制格式,它在google library中提供C ++,Java和Python,在community ports中提供C#,Perl,Ruby和其他格式?
请注意,Guid没有特定的数据类型,但您可以使用(基本上)byte[]
将其整理为消息。
通常,我建议使用protobuf-net(但作为作者,我有点偏颇) - 但是,如果您打算稍后使用其他语言,可能会使用Jon的dotnet-protobufs做得更好(长期);这将为您提供跨平台的熟悉的API(其中 - protobuf-net使用.NET惯用语。)
答案 1 :(得分:3)
ASCII字符0或1每个占用几个位(就像任何其他字符一样),所以如果你像那样存储它,你的“二进制”文件将比它应该大几倍。在0和1的文本文件中不完全是二进制文件:)
您可以使用BinaryWriter将原始数据直接写入file stream。您需要弄清楚的唯一部分是将内存中的格式(通常是某种对象图)转换为BinaryWriter可以使用的字节序列。
然而,如果您的主要兴趣是可移植性,我建议完全不使用二进制格式。 XML旨在解决可移植性和互操作性问题。它作为一种文件格式是冗长而重要的,但这是你为解决这些问题而做出的权衡。如果一个人类可读的格式不在桌面上,那么Marc's answer就是你要走的路。 。无需重新发明便携性轮!
答案 2 :(得分:2)
我会尝试添加一些用于创建便携式二进制文件格式的一般提示。
请注意,发明一种二进制文件格式意味着要记录它中的位必须如何以及它们的含义。它不是编码,而是文档。
现在的提示:
决定如何处理 endianess 。好的和简单的方法是一次又一次地决定它。当在普通PC(即x86)上使用时,选择最好是小端,以节省转换(性能)。
创建标题。是的,总是有一个标题是个好主意。文件的第一个字节应该能够告诉你,你正在搞什么格式。
最后,添加数据。现在,数据的格式将是具体的,它将始终基于您的确切需求。基本上,数据将存储在某些数据结构的二进制图像中。数据结构是您需要提出的。
如果您需要通过某种索引随机访问您的数据,documentation是可行的方法,而如果您只需要大量数字来编写所有数据,那么就可以全部读取它们。阵列"会做的。
此外,您可以使用B-Trees概念进行向前兼容。
答案 3 :(得分:1)
这取决于您将要写入二进制文件的数据类型以及二进制文件的用途。它们是类对象还是仅记录数据?如果是记录数据,我建议将其放入xml格式。这样,您可以包含模式验证,以验证文件是否符合您的标准。 java和.NET中都有工具可以从/到xml格式导入和导出数据。
答案 4 :(得分: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
}
然后我会有一个顺序文件:
byte // a
byte // b
int //名称大小
char [] // name(具有上面指定的大小,记住一个char在.NET中是16位)
int // MyTypeEnum type
int //数据大小
byte [] // data(具有上面指定的大小)
然后你可以根据需要重复最后三行。
要阅读,请使用支持读取字节,整数和字节序列的BinaryReader
。还有BinaryWriter
。
此外,请记住,Microsoft .NET(因此在Windows / Intel机器上)是小端的。 BinaryReader
和BinaryWriter
也是如此。