【问题标题】:A C style string file format conundrum一个 C 风格的字符串文件格式难题
【发布时间】:2009-10-18 14:26:30
【问题描述】:

我对我遇到的这个小问题感到非常困惑。我有一个非索引文件格式标题。 (更具体地说是 ID3 标头)现在,此标头存储一个字符串,或者更确切地说是三个字节,以确认数据实际上是一个 ID3 标记(TAG 是字符串顺便说一句。)重点是,现在文件中的这个 TAG格式不是以空值结尾的。所以有两件事可以做:

  • 使用fread 加载整个文件,对于非终止字符串比较,使用strncmp。但:
    1. 这听起来很老套
    2. 如果有人打开它并试图在没有事先了解的情况下操纵字符串怎么办?
  • 另一个选项是加载文件,但 C 结构不应完全映射到文件格式,而是包含适当的空终止符,然后应使用唯一调用加载每个成员。但是,这也感觉很hacky并且很乏味。

非常感谢您的帮助,尤其是有处理此类问题的实际经验的人提供的帮助。

【问题讨论】:

    标签: c string data-structures file-format null-terminated


    【解决方案1】:

    解析任何内容时首先要考虑的是:这些字段的长度是固定大小还是以计数为前缀(它们本身的大小是固定的,例如,几乎每个图形文件都有固定大小/结构的标题后跟可变大小的像素序列)?或者,格式是否具有以某种方式分隔的完全可变长度字段(例如,MPEG4 帧由字节 0x00、0x00、0x01 分隔)?通常,这个问题的答案将大大有助于告诉您如何解析它。

    【讨论】:

      【解决方案2】:

      如果文件格式规范说某个三个字节的值对应于“T”、“A”、“G”(84、65、71),那么您应该只比较这三个字节。

      对于这个例子,strncmp() 是可以的。一般来说,memcmp() 更好,因为它不必担心字符串终止,因此即使您正在比较的字节流(标签)包含 ASCII NUL '\0' 字符,memcmp() 也可以工作。

      您还需要识别您使用的文件格式主要是可打印数据还是主要是二进制数据。用于可打印数据的技术可能与用于二进制数据的技术不同;用于二进制数据的技术有时(但并非总是)转换为用于可打印数据。一个很大的区别是二进制数据中值的长度是预先知道的,要么是因为长度嵌入在文件中,要么是因为文件的结构是已知的。对于可打印数据,您通常会处理字段上具有隐式边界的可变长度编码 - 并且前面没有长度编码信息。

      例如,Unix 密码文件格式是具有可变长度字段的文本编码;它使用“:”来分隔字段。在遇到下一个“:”或行尾之前,您无法判断字段有多长。这需要与使用 ASN.11 编码的二进制格式不同的处理方式,其中字段可以具有类型指示符值(通常是一个字节)和长度(可以是 1、2 或 4 个字节,具体取决于type) 在字段的实际数据之前。


      1 ASN.1(有理由)被认为非常复杂;我给出了一个非常简单的例子,大致说明了它是如何使用的,可以在多个层面上受到批评。然而,基本思想是有效的——长度(对于 ASN.1,通常也是类型)在(二进制)数据之前。这也称为TLV - 类型、长度、值 - 编码。

      【讨论】:

        【解决方案3】:

        如果你只是学习一些东西,你可以通过读取文件的最后 128 个字节,并检查块的前 3 个字符是否为TAG,在 MP3 文件中找到 ID3v1 标签。

        对于实际应用,请使用TagLib

        【讨论】:

        • 问题不在于特定的应用程序——它更像是什么应该是合适的方法——对于某种事情......
        • "what-should-be-the-approach-for" 始终取决于特定的文件格式。在大多数格式中,您知道在哪里查找标识符,或者至少明确定义了如何扫描文件以查找标识符。一旦你确定了你知道结构的块,你一次读取一个字段(然后它是否是固定大小、空终止等都无关紧要)。你永远不会用 C 结构解析文件。
        • @Lukáš Lalinský:“你永远不会用 C 结构解析文件。” ——这个说法有点太强了。我建议你看看 zlib。
        • 好吧,我确实查看了 zlib,但找不到将从文件读取的内存缓冲区映射到普通结构的代码。我能找到的只有指针操作、memcpy 和 get_byte/getLong/putLong 等函数。 :)
        【解决方案4】:

        保留三个字节并将每个字节与字符'T''A''G' 进行比较。这可能不是很聪明,但可以很好地完成工作,更重要的是正确。

        【讨论】:

        • 并且,对于解析特定的、众所周知的文件格式,请使用库。
        • 我说的是一个更笼统的东西——如果它是一个任意长的字符串呢?
        • 在编写文件格式解析器时,通常会使用众所周知的标签/元数据。另外,据我了解,您的代码是关于检测而不是解析。因此,上述方法就足够了。如果有一个任意长的字符串,标题很可能会有一个length 字段,以便您可以提前malloc 并读取数据。
        • @dirkgently 所以,在我看来,没有办法不必手动编写数据的每个字段?
        • @aviraldg:嗯,这取决于您要达到的目标。您必须阅读,是否保存信息将取决于您的要求。
        【解决方案5】:

        别忘了 id3 v1 和 id3v1.1 上两种不同含义的流派

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-10-23
          • 2011-05-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多