可能有许多库可以处理特定文件格式,例如 tar 的变体,但没有一个库可以适应您的特定标头格式。
首先,您需要确定您的元数据是固定大小还是可变大小。
如果是固定大小,在开始的时候跳过那么多字节,写入文件的其余部分,然后倒带并填写元数据,是相对容易的。如果一开始就知道唯一可变大小的部分,您可以以大致相同的方式处理它 - 编写第一个版本,然后在完成后返回并编写最终版本。
如果你直到最后才知道可变材料的大小,你就遇到了一些困难。您可能最终会使用大部分文件编写一个临时文件,然后当您完成并知道所有可变大小的元数据后,您将元数据头写入一个新的(最终)文件,然后在元数据。
请注意,在磁盘上的数据中,您应该将文件名的大小(长度)放在实际文件名之前。然后你可以读取名称有多大,并分配正确的空间并读取正确的数据量。将文件名的长度放在文件名本身之后确实没有多大帮助。
您还需要考虑您的标题是二进制数据还是文本。文件名部分将是文本,但数字可以是 2 字节或 4 字节二进制值,或 ASCII(纯文本)可变长度等效项。调试文本表示通常更容易,但如果您确实使用文本,则更有可能需要可变长度数据。但是,您也可以始终使用带有空白填充的固定大小。文本相对于二进制的另一个优势是文本可以跨机器架构移植,而二进制则带来了大端与小端机器的问题,等等。
您还应该考虑使用“幻数”来识别文件是否包含正确类型的数据。 “数字”可能是一个 ASCII 字符串,例如在某些版本的 ar 标头中使用的 !<arch>\n。或者在 PDF 文件开头使用的%PDF-1.3\n。话虽如此,tar 在第一个字节中基本上没有一个幻数,但如今这是一个不寻常的设计。 file 程序非常了解幻数。有时可以在文件中找到其数据 - 例如 Mac OS X 的 /usr/share/file 下的文件。
你能举个例子解释一下吗?
我处理的一种文件格式是用于由 32 位(有符号)数字标识的消息,消息的长度可变,因此偏移量可变。该文件以与平台无关的二进制格式编写。这些数字是大端的,首先是 MSB。消息数量目前被限制在 ±99,999 范围内(因此整个系统中只有不到 200,000 条消息的空间)。
文件头包含:
- 2 字节(无符号)幻数
- 文件中包含的消息数的 2 字节(无符号)计数,N
后面是N个条目,每个条目描述一个消息:
- 4 字节(有符号)消息编号
- 2 字节(无符号)消息长度
- 消息开头的 4 字节(无符号)偏移量
N 个条目按消息编号排序,但不要求消息编号连续。缺少的数字只是缺少。
在 N 个条目之后,是实际的消息文本,每个由相应条目标识的适当数量的字节加上一个 ASCII NUL '\0' 字节组成。
在生成文件时,每条消息的文本都会按处理顺序写出到中间文件,记录文件中消息的偏移量。消息是按顺序读取还是写入并不重要;重要的是从标题末尾的偏移量记录在标题记录中。读入所有消息后,可以将文件条目的内存副本按数字顺序排序,然后可以写入最终文件。首先是幻数和消息数;然后是描述消息的 N 个条目;后面是从中间文件复制的消息文本。
读取消息编号 M 很简单。您对 N 个条目进行二进制搜索以找到 M 的条目。如果它不存在,那就这样吧 - 这是一个错误。如果它在那里,您就知道在文件中的何处找到它以及它有多长。
数据是固定的二进制格式这一事实并没有真正使事情复杂化。您在 big-endian 和 little-endian 机器上使用相同的函数将数字读入本机格式。理论上,您可以针对大端机器进行优化,但前提是该机器没有对齐数据不足的问题。忘记优化可能是可能的并且在任何地方都使用相同的代码更简单。
如果将上述格式转换为文本格式,那么它可能会保留 8 个字节(比如说)用于幻数(很可能是一个 7 个字母的字符串后跟一个换行符),并保留 6 个字节用于消息的数量(5 位数字加上换行符)。每个消息条目可以为消息号保留 6 个字节(数字为 ±99,999),加上一个空格,再加上 4 个字节的长度(最大,8KiB)加上一个空格,加上一个 8 个字节的偏移量(7 位加上换行符)。
MAGICNO
12345
-99999 8000 0000000
-90210 38 0008000
...
同样,文本文件的可读性优势在于您可以很容易地查看文件并了解数据的含义。
你可以在这个主题上有无穷无尽的变化。