我正在使用C中的POSIX API系统调用创建文件存档器/提取器(如tar).我已经完成了部分存档位.
我想知道是否有人可以帮助我使用一些C源代码(使用上面的代码)为C中的文件创建文件头(其中头部充当索引),它描述了文件属性/元数据(名称,日期时间等).到目前为止我所做的只是理解(不确定是否正确)创建文件头它需要一个结构来保存元数据,并且需要lseek来寻找文件的开头/结尾,如:
FileName = file.txt FileSize = 0
FILEDIR =./等等/等等
FilePerms = 000
\n \n
程序的归档部分有这个过程:
即使我知道它需要做什么,我也难以创建整个头文件,正如我所说的那些位上面的编号点所述(2,3,4,6,7).
任何帮助将不胜感激.谢谢.
正如ijw所说,有几种方法可以创建存档文件头.如果跨平台可移植性将成为一个问题 - 或者如果您需要在同一平台上的32位和64位版本的软件之间切换,那么您需要确保尺寸和布局所有平台都完全理解这些字段.
一种方法是使用具有已知大小和字节序类型的固定格式二进制头.这是ijw建议的.但是,您需要处理长文件名,因此您需要存储长度(可能是2字节无符号整数),然后使用实际路径名.
替代的,通常现在有利的技术,是使用可打印的字段(通常称为ASCII格式,尽管这是用词不当).时间记录为自Epoch转换为字符串以来的十进制秒数等.这是现代ar档案馆使用的; 它是GNU tar所做的(或多或少;有一些历史怪癖会让人更加困惑); 这是什么cpio -c(这些日子通常是默认的).字段可能由空值或空格分隔; 有一种简单的方法可以检测标题的结尾; 标题包含有关文件名的信息(不一定是您希望或期望的直接信息,但同样,这通常是因为格式已经发展了多年),然后是实际数据.不知何故,您知道每个字段的大小以及标头描述的文件,以便您可以可靠地读取数据.
效率是一个红鲱鱼.与第一个磁盘访问相比,与文本格式的转换非常迅速,基本上没有可测量的性能问题.保证可移植性通常远远超过使用二进制数据格式的(微观)性能优势 - 当二进制数据必须在输入或输出上进行转换以使其成为体系结构中立格式时更是如此.
要考虑的另一个问题是归档中的文件索引是集中的(在前面还是在末尾)还是分布式的(每个文件的元数据紧接在文件的数据之前).每种格式都有一些优点 - 通常,系统使用分布式版本,因为您可以为每个文件编写信息,而无需知道总共要处理多少文件(例如,因为您递归地归档目录的内容).预先设置中央索引意味着您可以在不读取整个存档的情况下列出文件 - 分布式元数据意味着您必须读取整个文件.但是,中央索引使归档的构建变得复杂.
请注意,即使使用分布式索引,您通常也需要整个存档的标题,以便您可以检测到文件的格式符合您的预期.通常,存在某种标记信息(!<arch>\n对于ar存档,通常; %PDF-1.2\n在PDF文件的开头等),以向您保证文件包含您期望的内容.可能存在一些整体(存档级)元数据.然后,您将获得第一个文件元数据,后跟文件数据,重复直到存档结束(可能或可能不具有正式结束标记 - 更多元数据).
[H]我会在你建议的'固定格式二进制标题'中实现它.我在决定需要哪些命令/功能时遇到问题.
我打算建议你不要使用固定格式的二进制头文件; 您应该使用基于文本的标题格式.如果你能弄清楚如何做二进制格式,那就做我的客人(多年来我做过很多次 - 这并不意味着我认为这是一个好主意).
所以,这里有一些关于'text header'格式的指针.
对于文件元数据,您可以定义包括:
您可以合理地确定您的文件大小限制为64位无符号整数,这意味着20个十进制数字.该模式可能打印为16位八进制数,需要6个八进制数字.所有者和组可能会打印为UID和GID值(而不是名称),在这种情况下,您可以使用10位数字.或者,您可以决定使用名称,但是您应该允许每个名称最多32个字符.请注意,名称通常比数字更便携.除非您以root身份提取数据,否则名称和数字都不会与接收计算机相关(但为什么要这样做呢?).修改时间通常是32位有符号整数,表示自Epoch(1970-01-01 00:00:00Z)以来的秒数.您应该通过允许秒数增长大于32位数量来允许Y2038错误; 你可能会认为12个领先的数字将超过Y10K危机(大约4个左右),这已经足够了; 你可能决定允许小数秒.总之,这表明时间戳的26个空格应该是矫枉过正的.您可以决定每个字段将通过空格与下一个字段分开(为了易读 - 请考虑"易于调试"!).您可以合理地确定所有文件名的总长度限制为4位小数.
你需要知道如何便携地格式化类型 - #include <inttypes.h>是你的朋友.
然后,您可以设计用于打印(写入)文件元数据的格式字符串,以及用于扫描(读取)文件元数据的并行字符串.
印刷:
"%20" PRIu64 " %06o %-.32s %-.32s %26" PRIu64 " %-4d %s\n"
Run Code Online (Sandbox Code Playgroud)
这也打印出名称.它用换行符终止标题.总大小为127个字节加上文件名的长度.这可能是过度的,但你可以调整数字以适合自己.
扫描:
"%" SCNu64 " %o %.32s %.32s %" SCNu64 "%d"
Run Code Online (Sandbox Code Playgroud)
这不会扫描名称; 您需要仔细创建名称扫描程序,尤其是因为您需要读取名称中的空格.实际上,扫描用户名和组名的代码也都没有空格.如果这是不可接受的(即名称可能包含空格),那么您需要更复杂的扫描格式,或者除了sscanf()处理输入数据之外的其他格式.
我假设时间字段为64位整数,而不是混合小数秒等,即使有足够的空间允许小数秒.你可能会在这里节省一些空间.