【问题标题】:Simple API for random access into a compressed data file用于随机访问压缩数据文件的简单 API
【发布时间】:2011-03-10 17:33:54
【问题描述】:

请推荐适合以下任务的技术。

我有一个相当大的 (500MB) 数据块,它基本上是一个数字矩阵。数据熵很低(它应该是可良好压缩的)并且存储在它所在的地方很昂贵。

我正在寻找的是使用良好的压缩算法(例如 GZip)对其进行压缩,并带有可以实现非常偶然的随机访问的标记。随机访问,如“从原始(未压缩)流中的位置 [64 位地址] 读取字节”。这与 ZLIB 等经典的压缩器库略有不同,后者可以让您连续解压缩流。我想要的是在延迟的情况下进行随机访问,例如,每个字节读取最多 1MB 的解压缩工作。

当然,我希望使用现有的库而不是重新发明 NIH 的轮子。

【问题讨论】:

    标签: c++ compression gzip random-access


    【解决方案1】:

    我认为压缩算法通常以块为单位工作,因此您也许可以根据块大小提出一些建议。

    【讨论】:

    • 虽然原始数据以块为单位进行处理,但压缩后的数据块大小不同,因此您无法在压缩数据中跳转以查找特定块。
    • 如果文件被分成块,每个块代表 65,536() 字节的源数据,那么每个块可以在一张表上花费四个字节来说明每个块的开始位置。 () 也可以使用 1,048,576 字节的块大小,但即使使用 64K 块,半 gig 文件也只需要 32Kbyte 表。
    【解决方案2】:

    我建议使用Boost Iostreams Library。 Boost.Iostreams 可用于创建流以访问 TCP 连接或用作加密和数据压缩的框架。该库包括用于访问内存映射文件、使用操作系统文件描述符进行文件访问、代码转换、使用正则表达式进行文本过滤、行尾转换以及 zlib、gzip 和 bzip2 格式的压缩和解压缩的组件。

    Boost 库已被 C++ 标准委员会接受为 TR2 的一部分,因此最终将内置于大多数编译器 (under std::tr2::sys)。它也是跨平台兼容的。

    Boost Releases

    Boost Getting Started Guide 注意:只有boost::iostreams 的某些部分是仅标头库,在链接时不需要单独编译的库二进制文件或特殊处理。

    【讨论】:

    • boost::iostreams 不是仅标头库;虽然它的一部分是。
    【解决方案3】:

    Byte Pair Encoding 允许随机访问数据。

    你不会得到那么好的压缩,但是你会牺牲自适应(可变)哈希树来换取一棵树,所以你可以访问它。

    但是,您仍然需要某种索引才能找到特定的“字节”。由于您可以接受 1 MB 的延迟,因此您将为每 1 MB 创建一个索引。希望您能找到一种方法使您的索引足够小,以便仍然从压缩中受益。

    这种方法的好处之一是随机访问编辑。您可以更新、删除和插入相对较小的数据块。

    如果它很少被访问,你可以使用 gzip 压缩索引并在需要时对其进行解码。

    【讨论】:

    • 你能给我推荐一个现有的实现吗?
    【解决方案4】:

    如果您想最大程度地减少所涉及的工作,我只需将数据分成 1 MB(或其他)的块,然后将这些块放入 PKZIP 存档中。然后,您需要一点前端代码来获取文件偏移量,然后除以 1M 以获得要解压缩的正确文件(显然,使用余数来获得该文件中的正确偏移量)。

    编辑:是的,有现有的代码可以处理这个问题。 Info-zip 的 unzip 的最新版本(6.0 是当前版本)包括api.c。其中包括UzpUnzipToMemory - 您将ZIP 文件的名称以及您想要检索的档案中的一个文件的名称传递给它。然后,您将获得一个保存该文件内容的缓冲区。要进行更新,您将需要 zip3.0 中的 api.c,使用 ZpInitZpArchive(尽管这些不像解压缩端那样简单)。

    或者,您可以在后台运行 zip/unzip 的副本来完成这项工作。这不是很整洁,但无疑实现起来更简单(如果您愿意,还可以很容易地切换格式)。

    【讨论】:

    • 这是个好主意。不幸的是,我不知道有任何现有的库可以做到这一点,但使用包装类很容易实现。
    • 编辑数据可能有点棘手,但它是可行的。
    【解决方案5】:
    1. 大文件先排序
    2. 将其分成您希望大小 (1MB) 的块,并在名称中包含一些序列(File_01、File_02、..、File_NN)
    3. 从每个块中获取第一个 ID 加上文件名,并将这两个数据放入另一个文件中
    4. 压缩块
    5. 您将能够使用您希望的方法对 ID 文件进行搜索,可以是二进制搜索并根据需要打开每个文件。

    如果您需要深度索引,您可以使用 BTree 算法,其中“页面”是文件。 在网络上存在几个实现,因为代码有点棘手。

    【讨论】:

    • 如果我们有索引,我认为我们不需要多个压缩文件。
    • Gustavo,谢谢,但我知道如何自己设计。我需要有人把我指向一个现有的图书馆……我不能成为第一个遇到这个问题的人……
    【解决方案6】:

    如果您使用 Java,我刚刚为此发布了一个库:http://code.google.com/p/jzran

    【讨论】:

      【解决方案7】:

      您可以使用 bzip2 并根据 James Taylor 的 seek-bzip2 轻松制作自己的 API

      【讨论】:

        【解决方案8】:

        看看我的项目 - csio。我认为这正是您正在寻找的:包括标准输入输出接口和多线程压缩器。

        它是一个库,用 C 语言编写,提供 CFILE 结构和函数cfopencfseekcftello 等。您可以将它与常规(未压缩)文件和在 dzip 实用程序的帮助下压缩的文件一起使用。该实用程序包含在项目中并用 C++ 编写。它生成有效的 gzip 存档,可以由标准实用程序以及 csio 处理。 dzip 可以在多个线程中压缩(参见-j 选项),因此它可以非常快速地压缩非常大的文件。

        典型用法:

        dzip -j4 myfile
        
        ...
        
        CFILE file = cfopen("myfile.dz", "r");
        off_t some_offset = 673820;
        cfseek(file, some_offset);
        char buf[100];
        cfread(buf, 100, 1, file);
        cfclose(file);
        

        它是 MIT 许可的,因此您可以在您的项目中不受限制地使用它。更多信息请访问github上的项目页面:https://github.com/hoxnox/csio

        【讨论】:

          猜你喜欢
          • 2012-12-22
          • 1970-01-01
          • 2021-09-25
          • 1970-01-01
          • 2012-03-10
          • 1970-01-01
          • 1970-01-01
          • 2015-05-05
          • 1970-01-01
          相关资源
          最近更新 更多