|
|
1
27
看一看 PNG spec .这种格式背后有一些很好的理由。 此外,决定什么对你未来的格式很重要:紧凑性、兼容性,允许在其中嵌入其他格式(不同的压缩算法)。另一个有趣的例子是 Google's protocol buffers ,其中传输数据的大小是最重要的。 至于endianness,我建议您选择一个选项并坚持使用,不允许使用不同的字节顺序。否则,读写库只会变得更复杂、更慢。 |
|
|
2
18
我同意这些都是好主意:
但是你的第四个版本太夸张了,因为#2允许你添加字段,只要你更改版本号(并且只要你不需要) forward compatibility ).
此外,在文件上施加块结构的想法(用许多其他答案表达)似乎不像是对二进制文件的通用要求,而是对特定类型有效负载问题的解决方案。 除了上面的1-3条,我还要补充这些:
|
|
|
3
11
当然,这完全取决于格式的目的。 一种灵活的方法是将整个文件构造为TLV(标记长度值)三元组。 例如,将文件压缩为多条记录,每条记录以4字节的头开头:
关于endianness,如果在文件中存储endianness指示符,那么所有应用程序都必须支持所有endianness格式。另一方面,如果为文件指定特定的endianness,则只有在具有不匹配endianness的平台上的应用程序才能执行额外的工作,并且可以在编译时决定(使用条件编译)。 |
|
|
4
7
另一点,摘自。xz文件规范( http://tukaani.org/xz/xz-file-format.txt ):前几个字节中的一个应为非字符,“以防止应用程序将文件误检测为文本文件。”。请注意,编辑器和其他工具通常会检查多少头字节,但在前四个或八个字节中使用非二进制字节似乎很有用。 |
|
|
5
3
未来证明文件的一种方法是提供块。在文件头数据之后,可以直接开始第一个块。块可以有块类型的字节或字代码,然后是以字节为单位的大小。现在可以任意添加新的块类型,并且可以跳到块的末尾。 |
|
|
6
3
我会考虑定义一个更高级别的子结构来存储数据,有点像文件里面的一个迷你文件系统。 例如,即使您的文件格式将存储特定于应用程序的数据,我也会考虑在文件中定义记录/流等,这样应用程序不可知代码能够理解文件的布局,但当然不能理解不透明的有效载荷。 让我们更具体一点。考虑在内存中存储数据的常用方法:一般来说,它们可以被煮沸到相邻的可扩展数组/列表、指针/基于引用的图形和特定格式的二进制数据块。 因此,按照类似的思路定义二进制文件格式可能会很有成效。使用记录头,指示以下数据的长度和组成,无论是数组(类型相同的记录列表)、引用(到文件中其他记录的偏移量)还是数据块(例如,特定编码的字符串数据,但不包含任何引用)。 如果精心设计,这不仅可以让文件格式一次保存数据,还可以根据需要增量保存数据。如果子结构设计正确,它可以不依赖于应用程序,但仍然允许编写垃圾收集应用程序,该应用程序可以理解blob、数组和引用记录类型,并且能够跟踪文件并消除未使用的记录(即不再指向的记录)。 这只是一个想法。其他可以寻找想法的地方是通用文件系统设计,或关系数据库物理存储策略。 当然,根据你的要求,这可能有些过分。您可以简单地使用二进制格式来保存内存数据,在这种情况下,要考虑的方法是标记记录。 在这种方法中,每段数据都以一个标记作为前缀。标记指示紧跟其后的数据的类型,可能还指示其长度和名称。列表的后缀可能是一个没有有效负载的“结束列表”标记。标记可能有一个嵌入的标识符,因此序列化机制在读取中的内容时可以忽略不理解的标记。在这方面,它有点像XML,只是使用了二进制习惯用法。 实际上,XML是一个寻找文件格式长期有效性的好地方。看看它的名称空间功能。如果仔细构造读写代码,应该可以编写应用程序来保留他们不理解的标记(递归)数据的位置和内容,这可能是因为它是由同一应用程序的更高版本编写的。 |
|
|
7
3
确保保留一个标记代码(最好在每个标记中保留一个位),用于指定已删除/空闲的块/区块。 然后,只需将块的当前标记代码更改为已删除的标记代码或设置标记的已删除位,即可删除块。 这样,当你删除一个块时,你就不需要马上完全重组你的文件。 在标记中保留一个位提供了可能取消删除块的选项 (如果保持块的数据不变)。 然而,为了安全起见,您可能希望将已删除块的数据归零,在这种情况下,您将使用一个特殊的删除/释放标记。 我同意Stepan的观点,你应该选择一个endianess,但我也会在文件中有一个endianess指示符。 如果你使用了一个字节索引,你可以考虑使用 其中一个 UniCode Byte Order Marks 也可作为用于任何文本块的任何UniCode文本编码的索引。BOM表通常是UniCode文本文件的前几个字节,因此,如果BOM表是文件中的第一个条目,则可能会出现一些实用程序将文件标识为UniCode文本的问题(我认为这不是什么问题)。 我会将BOM表视为一个普通的标记(如果使用16位标记,则使用UTF16 BOM;如果使用32位标记,则使用UTF32 BOM),并保留一个0长度的块/区块。 |
|
|
8
3
在开始之前要知道的最重要的事情之一是如何使用文件。
这里的大多数答案在可移植性/兼容性方面给出了很好的建议,所以我不打算再补充更多。但是考虑下面的(经常被忽视的)事情。
有很多事情需要记住,设计一个好的格式需要大量的计划和远见。比如
|
|
|
9
2
我同意atzz关于使用标签长度值系统的建议。为了将来的兼容性,您可以在开始时存储一组指向TLV条目的“指针”(或者标记、指针并使指针指向一个长度、值;或者标记、长度、指针,然后将所有数据放在一起?)。 所以,我的文件可能看起来像:
幻数、版本、标签、指针和长度都是预定义的设置长度,便于解码。比如说,2字节。或者4,取决于你需要什么。它们并不都需要相同(例如,所有标记都是1字节,指针都是4字节等等)。 这个 标签 让您知道存储的内容。这个 指针 告诉您 长 告诉您数据有多大,以及 价值 是 长 类型的数据字节数 标签 . 如果在MyFileFormat v2文件上使用MyFileFormat v1解码器,指针允许您跳过v1解码器无法理解的部分。如果您只是跳过无效的标记,那么您可能只需要使用TLV而不是TPLV。 我要么手工编写这样的代码,要么用 ASN.1 并生成一个编解码器(我在电信行业工作,所以ASN.1/TLV对我来说是有意义的:-D) |
|
|
10
2
如果你处理的是可变长度的数据,那么 很 更有效地使用指针:最好在文件开头附近有一个指向数据的指针数组,而不是直接将数据存储在数组中。 在这种情况下,间接寻址更可取,因为它允许随机访问,这只有在所有项大小相同的情况下才可能实现。如果数据直接存储在一个数组中,而不指定任何记录的位置,那么数据访问将需要( N )在最坏的情况下是时间;为了让你的文件读取代码访问一个特定的元素,它必须知道之前所有元素的长度,唯一的方法是查看每个元素。如果您同时读取整个文件,那么无论如何您都会这样做,所以这不会是一个问题。但是如果你只想要一件事,那么这不是你想要的方式。 而对于指针数组,则是O(1)时间:您只需要一个索引号,就可以检索并跟踪指针以获取数据。 当使用这种方法写入文件时,在进行任何写入之前,您当然必须在内存中建立表。 |
|
|
D W · Python-将浮点数从2转换为10到100位小数 1 年前 |
|
|
NScara · 从Python中的二进制值解压缩文件[关闭] 2 年前 |
|
|
cake2244 · R中的应急表[副本] 2 年前 |
|
|
Linh Chi · 如何调试用于二进制搜索的Javascript代码 2 年前 |
|
|
GoodCat · 如何将这64行缩短4个字符? 3 年前 |