7z单文件存档中的随机搜索

5

能否对由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算法进行压缩。测试中解压速度为600MB/s(对应未压缩数据),仅使用了一个CPU核心。


还有一个有趣的 xz 变体,vasi 的 pixz,它可以将文件打包成多个块,并添加流索引以进行快速查找(通常用于在 tar.xz 中进行快速查找):https://github.com/vasi/pixz。"*Pixz 生成一系列较小的块,使得对原始数据进行随机访问成为可能。这对于大型 tarballs 特别有用。*" - osgx
4个回答

3
技术上是可能的,但如果你的问题是“当前可用的二进制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。您能否从我的文件头中说出使用的块大小? - osgx
1
7zip不会对输入文件进行“分块”,因此这是一个单块,使用“滑动窗口”方法压缩。你将面临的问题是,7zip之所以有出色的压缩比率是因为它将你的文件作为一个单块压缩了。如果你将文件分成小块,并逐个使用7zip压缩它们,就不会得到相同的结果。不幸的是,获得文件的任何部分的直接访问的唯一方法是首先将其分成小块。因此,这就是困境... - Cyan

1
7z压缩工具表示此文件具有单个数据块,使用LZMA算法进行压缩。
如何使用7z / xz命令查找是否为单个压缩块?当使用多个线程时,7z是否会创建多块(多流)存档?
原始文件非常巨大(999GB XML)。
好消息是:维基百科已经切换到多流存档以进行转储(至少对于enwiki):http://dumps.wikimedia.org/enwiki/ 例如,最近的转储http://dumps.wikimedia.org/enwiki/20140502/具有多流bzip2(带有单独的索引“offset:export_article_id:article_name”),而7z转储存储在许多子GB存档中,每个存档包含约3k(?)篇文章。

Articles, templates, media/file descriptions, and primary meta-pages, in multiple bz2 streams, 100 pages per stream

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

All pages with complete edit history (.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
我认为我们可以使用bzip2索引来估算文章ID,即使是7z转储文件,然后我们只需要具有正确范围(..p first_id p last_id .7z)的7z存档。 stub-meta-history.xml 也可能会有所帮助。
转储的常见问题解答: http://meta.wikimedia.org/wiki/Data_dumps/FAQ

有趣的是,bzip2文件可以被索引,而无需多个串联流,因为它们始终位于以标记开头的块中。 - hippietrail

1

这样怎么样:

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

逐块读取压缩文件,在数据流中为每个块分配一个编号和可能的大文件偏移量。扫描数据流中的目标项锚点(例如维基百科文章标题)。对于每个锚点记录,保存该项开始的块号(可能在前一个块中)

将索引写入某种 O(log n) 存储。对于访问,检索块号及其偏移量,提取块并查找该项。成本限制为提取一个块(或非常少量块)和该块中的字符串搜索。

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

DARN:您基本上在问题中假设了这一点...在回答之前阅读问题似乎是有优势的...


sleeplessnerd,这里的问题是:“这个7z归档文件有多个块还是只有一个块?”我建议它只有一个块。 - osgx
1
1分钟的研究表明,LZMA的一个特性是它支持非常大的字典(>1GB),因此它可能是一个连续的块。 - sleeplessnerd
刚刚检查了一下,我的文件只有一个块。我该如何从归档中找到压缩时使用的字典大小?在测试中,7zfm 的内存使用量为 25 MB。 - osgx

1

仅使用:

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

获取第7行的示例:

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


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接