【问题标题】:Create file header (metadata of file) in C在 C 中创建文件头(文件的元数据)
【发布时间】:2012-03-09 05:17:52
【问题描述】:

文件头包含关于文件&mdash的所有数据;元数据。我想创建一个带有元数据的空白文件,然后我想将其他文件内容添加到这个空白文件并需要更改(修改)元数据。 C中是否有任何用于创建文件头的库?如何在 C 中读取/写入文件头?

metadata = {
    file_name;
    file_size;
    file_type;
    file_name_size;
    total_files;
}

【问题讨论】:

  • 我怀疑file_name。在不知道文件名的情况下如何获取文件名?
  • @PavanManjunath:文件必须有名称,我正在创建空白文件,表示数据为空白而不是文件名!!!

标签: c file file-io


【解决方案1】:

可能有许多库可以处理特定文件格式,例如 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
...

同样,文本文件的可读性优势在于您可以很容易地查看文件并了解数据的含义。

你可以在这个主题上有无穷无尽的变化。

【讨论】:

  • 谢谢,你能举个例子解释一下吗?我不知道变量的大小。
  • 是否有任何解决方案可以将其他目录详细信息存储到我的文件头中??文件名、文件大小和文件数。
  • 当然——有很多方法可以存储目录详细信息。你只需要适应我概述的想法。您决定存储哪些数据;您决定将使用的格式;您将数据转换为正确的格式;你写它。确定正确的格式包括确保您知道程序如何再次明确地读取数据。您可以使用固定大小的字段(如果数据很短,则使用适当的填充)或使用 TLV(类型-长度-值)编码。类型可能是隐式的;主要的可变长度字段将是文件名。
【解决方案2】:

int stat(const char *path, struct stat *buf); 可以为您提供有关文件的以下信息

struct stat {
    dev_t     st_dev;     /* ID of device containing file */
    ino_t     st_ino;     /* inode number */
    mode_t    st_mode;    /* protection */
    nlink_t   st_nlink;   /* number of hard links */
    uid_t     st_uid;     /* user ID of owner */
    gid_t     st_gid;     /* group ID of owner */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size;    /* total size, in bytes */
    blksize_t st_blksize; /* blocksize for file system I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime;   /* time of last access */
    time_t    st_mtime;   /* time of last modification */
    time_t    st_ctime;   /* time of last status change */
};

如果按文件类型,你的意思是windows对文件扩展名的感觉,那么你无论如何都可以通过读取文件名来获得它。

【讨论】:

  • 我可以更改文件的保护模式(st_mode)吗??
  • @Nimit 是的,如果您(或您的程序)是/是您想要更改其权限的文​​件的所有者。以下是 st_mode 可以采用的不同值 delorie.com/gnu/docs/glibc/libc_288.html
  • 我可以将目录更改为文件吗??
  • AFAIK 你不能。您可以删除目录并创建一个同名文件:)
【解决方案3】:

最简单的方法是将其存储为结构,然后保存并按原样读取。如果您支持多个版本,可能会有点棘手,但有可能,请记住在开始时存储某种版本标签。结构如下:

struct metadata = {
    file_name;
    file_size;
    file_type;
    file_name_size;
    total_files;
} data;

然后你可以使用 fwrite 命令保存,并使用 freed 命令读取,首先打开一个文件,然后:

fwrite(data,sizeof(metadata),1,FILE_POINTER);

fread(data, sizeof(metadata), 1, FILE_POINTER);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多