如何获得 gzip 压缩文件的随机访问
Posted
技术标签:
【中文标题】如何获得 gzip 压缩文件的随机访问【英文标题】:How to obtain random access of a gzip compressed file 【发布时间】:2014-04-08 23:18:14 【问题描述】:根据this FAQ on zlib.net 可以:
在压缩流中随机访问数据
我知道Biopyton 1.60的模块Bio.bgzf,其中:
支持读取和写入 BGZF 文件(Blocked GNU Zip Format),这是一种具有高效随机访问的 GZIP 变体,最常用作 BAM 文件格式和 tabix 的一部分。这在内部使用了 Python 的 zlib 库,并提供了类似于 Python 的 gzip 库的简单接口。
但对于我的用例,我不想使用那种格式。基本上我想要一些东西,它模拟下面的代码:
import gzip
large_integer_new_line_start = 10**9
with gzip.open('large_file.gz','rt') as f:
f.seek(large_integer_new_line_start)
但是通过本机 zlib.net 提供的效率来提供对压缩流的随机访问。如何利用 Python 中的随机访问功能?
【问题讨论】:
为什么不想使用 bgzip 压缩文件? bgzip 是有效的 gzip... @wkretzsch 我确实想使用 bgzip。我在3年前问过这个问题,所以我不太记得细节了。可能我正在使用的文件是 gzip 压缩的,而不是 bgzip 压缩的。 【参考方案1】:我放弃了使用 Python 对 gzip 压缩文件进行随机访问。相反,我将我的 gzip 压缩文件转换为在命令行上带有 block compression/decompression utility 的块 gzip 文件:
zcat large_file.gz | bgzip > large_file.bgz
然后我使用BioPython 并告诉获取bgzip压缩文件的第100万行的virtual_offset。然后我就可以快速找到 virtual_offset:
from Bio import bgzf
file='large_file.bgz'
handle = bgzf.BgzfReader(file)
for i in range(10**6):
handle.readline()
virtual_offset = handle.tell()
line1 = handle.readline()
handle.close()
handle = bgzf.BgzfReader(file)
handle.seek(virtual_offset)
line2 = handle.readline()
handle.close()
assert line1==line2
我还想在zlib 分布中的examples/zran.c 上指出SO answer by Mark Adler。
【讨论】:
【参考方案2】:您正在寻找dictzip.py
,它是serpento 包的一部分。但是,您必须使用dictzip
压缩文件,这是gzip
压缩的随机可搜索向后兼容变体。
【讨论】:
【参考方案3】:indexed_gzip 程序可能是您想要的。它还在后台使用zran.c
。
【讨论】:
【参考方案4】:如果你只是想从一个随机点访问文件,你不能这样做:
from random import randint
with open(filename) as f:
f.seek(0, 2)
size = f.tell()
f.seek(randint(0, size), 2)
【讨论】:
@scorpion-god 谢谢。我不想从随机点阅读。我希望能够访问 gzip 压缩文件中的任何点,而不必通读整个压缩流。 @tommy.carstensen 你不能传送。 @tommy.carstensen 更重要的是:这就是他们创建 BGZF 的原因,因为默认情况下 gzipped 不支持这一点。您仍然必须阅读整个内容一次才能构建索引。更多信息:***.com/questions/14225751/… @metatoaster 谢谢。我不介意阅读整篇文章来构建索引。如果我能弄清楚如何在我选择的任何文件格式上使用它,我将使用 BGZF。它似乎仅限于预先选择的一组文件格式。以上是关于如何获得 gzip 压缩文件的随机访问的主要内容,如果未能解决你的问题,请参考以下文章