在 7z 单文件存档中随机查找

Posted

技术标签:

【中文标题】在 7z 单文件存档中随机查找【英文标题】:random seek in 7z single file archive 【发布时间】:2011-10-24 21:41:28 【问题描述】:

是否可以对 7zip 压缩的非常大的文件进行随机访问(大量搜索)?

原始文件非常大(999gb xml),我无法以解压格式存储它(我没有那么多可用空间)。因此,如果 7z 格式允许访问中间块而无需解压缩所选块之前的所有块,我可以建立块开始索引和相应的原始文件偏移量。

我的 7z 存档的标题是

37 7A BC AF 27 1C 00 02 28 99 F1 9D 4A 46 D7 EA  // 7z archive version 2;crc; n.hfr offset
00 00 00 00 44 00 00 00 00 00 00 00 F4 56 CF 92  // n.hdr offset; n.hdr size=44. crc
00 1E 1B 48 A6 5B 0A 5A 5D DF 57 D8 58 1E E1 5F
71 BB C0 2D BD BF 5A 7C A2 B1 C7 AA B8 D0 F5 26
FD 09 33 6C 05 1E DF 71 C6 C5 BD C0 04 3A B6 29

更新:7z 存档器说这个文件有一个数据块,用 LZMA 算法压缩。测试解压速度为 600 MB/s(解压数据),仅使用一个 CPU 内核。

【问题讨论】:

还有一个有趣的xz变体,即vasi的pixz,它可以将文件打包成几个块,并为快速查找添加流索引(通常用于tar.xz中的快速查找): github.com/vasi/pixz "Pixz 会生成一组较小的块,这使得随机访问原始数据成为可能。这对于大型 tarball 尤其有用。" 【参考方案1】:

这在技术上是可行的,但如果您的问题是“当前可用的二进制 7zip 命令行工具是否允许这样做”,那么很遗憾,答案是否定的。 它允许的最好的方法是将每个文件独立压缩到存档中,从而允许直接检索文件。 但是由于您要压缩的是单个(巨大)文件,因此此技巧不起作用。

恐怕唯一的方法是将您的文件分成小块,然后将它们提供给 LZMA 编码器(包含在 LZMA SDK 中)。不幸的是,这需要一些编程技能。

注意:可以在此处找到技术上较差但微不足道的压缩算法。 主程序执行您正在寻找的工作:将源文件切成小块,并将它们一个一个地提供给压缩器(在本例中为 LZ4)。然后解码器执行相反的操作。它可以轻松跳过所有压缩块并直接转到您要检索的块。 http://code.google.com/p/lz4/source/browse/trunk/lz4demo.c

【讨论】:

lz4demo 意味着我需要重新打包完整的大文件? lz4的压缩级别与7zip相同吗?这个巨大的文件被 7zip/lzma/xz 打包,因为它太大了;即使在 bz2 中,它也不是 4GB,而是 14 GB。你能谈谈我的文件头中使用的块大小吗? 7zip 不会“分块”输入文件,所以这是一个单独的块,使用“滑动窗口”方法压缩。您将面临的问题是 7zip 具有出色的压缩率因为它将您的文件压缩为单个块。如果您将文件切成小块并使用 7zip 将它们一一压缩,您将不会得到相同的结果。不幸的是,直接访问文件任何部分的唯一方法是首先将其切成小块。因此陷入困境......【参考方案2】:

这个怎么样:

概念:因为您基本上只读取一个文件,所以按块索引 .7z。

逐块读取压缩文件,给每个块一个数字,可能还有一个大文件中的偏移量。扫描数据流中的目标项目锚点(例如***文章标题)。对于每个锚记录,保存项目开始的区块编号(可能在之前的区块中)

将索引写入某种 O(log n) 存储。对于访问,检索块编号及其偏移量,提取块并找到项目。成本必然是提取一个块(或很少)并在该块中进行字符串搜索。

为此,您必须通读文件一次,但您可以流式传输并在处理后丢弃它,因此不会影响磁盘。

DARN:你基本上在你的问题中假设了这一点......在回答之前阅读问题似乎很有利......

【讨论】:

sleeplessnerd,这里的问题是:“这个 7z 存档有很多块还是只有一个块?”。我建议它只有一个街区。 mmh 1min 研究表明 LZMA 的一个特性是它支持非常大的字典 (>1GB),因此它实际上可能是一个连贯的块。 刚刚检查过。我的文件有单个块。如何从存档中找到用于压缩的字典大小? 7zfm 在测试时的内存使用量为 25 MB。【参考方案3】:

7z 存档器说这个文件有一个数据块,用 LZMA 算法压缩。

7z / xz 命令是什么来查找它是否是单个压缩块? 7z 与多个线程一起使用时会创建多块(多流)存档吗?

原始文件非常大(999gb xml)

好消息:wikipedia 转储为多流档案(至少对 enwiki 而言):http://dumps.wikimedia.org/enwiki/

例如,最近的转储http://dumps.wikimedia.org/enwiki/20140502/ 具有多流 bzip2(具有单独的索引“offset:export_article_id:article_name”),并且 7z 转储存储在许多 sub-GB 档案中,每个档案大约有 3k (?) 篇文章:

多个 bz2 流中的文章、模板、媒体/文件描述和主要元页面,每个流 100 页

enwiki-20140502-pages-articles-multistream.xml.bz2 10.8 GB
enwiki-20140502-pages-articles-multistream-index.txt.bz2 150.3 MB

具有完整编辑历史记录的所有页面 (.7z)

enwiki-20140502-pages-meta-history1.xml-p000000010p000003263.7z 213.3 MB
enwiki-20140502-pages-meta-history1.xml-p000003264p000005405.7z 194.5 MB
enwiki-20140502-pages-meta-history1.xml-p000005406p000008209.7z 216.1 MB
enwiki-20140502-pages-meta-history1.xml-p000008210p000010000.7z 158.3 MB
enwiki-20140502-pages-meta-history2.xml-p000010001p000012717.7z 211.7 MB
 .....
enwiki-20140502-pages-meta-history27.xml-p041211418p042648840.7z 808.6 MB

我认为,即使对于 7z 转储,我们也可以使用 bzip2 索引来估计文章 id,然后我们只需要具有正确范围的 7z 存档 (..p first_id p last_id .7z)。 stub-meta-history.xml 也可能有帮助。

转储常见问题解答: http://meta.wikimedia.org/wiki/Data_dumps/FAQ

【讨论】:

有趣的是,bzip2 文件可以在没有多个连接流的情况下被索引,因为它们总是在以标记开头的块中。【参考方案4】:

只使用:

7z e myfile_xml.7z -so | sed [something] 

示例获取第 7 行:

7z e myfile_xml.7z -so | sed -n 7p

【讨论】:

你好。这将完全解包(或解包直到 SIGPIPE 一开始),并且我的存档非常大,解压后的文本大小为 999 GB(平均行长为 20 或 30 个 utf-8 字符)。有时我想要第 7 行,有时是第 10245-10345 行,有时是第 21453361643-21453361720 行。当我只想要接近归档末尾的 100 万行时,我不想在之前解压缩所有 200 亿行(需要半小时)。一些存档格式支持索引以允许此类访问(建立一次索引并使用它进行快速访问)。

以上是关于在 7z 单文件存档中随机查找的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Gin 在 HTTP 服务器中动态生成 zip/7z 存档?

仅使用 7z 压缩文件而不保留路径

命令行创建两个文件夹的 7z 存档和一个文件以自解压到指定位置

SharpCompress & LZMA2 7z 存档 - 特定文件的提取速度非常慢。为啥?备择方案?

sh 简单的sha256位加密存档用于保护重要文件,因为7z命令通常很难记住。

随机生成一份试卷,试卷的种类分为单选多选判断三种题型。nodejs6.0 mysql