如何 decompress/decrypt gzip 文件的单行

How to decompress/decrypt a single line of a gzip file

这里的症结在于这是一个巨大的文件。我的目标是避免一次将整个文件读入内存,并避免在循环中解析每一行以到达我需要的行(因为它需要永远。文件实际上有 1500 万行)。

我目前正在做的是将文件打开为...

self._FH = gzip.open(filename, "rb")

...将指针直接移动到所需行的位置(使用许多恶作剧,但它有效)并读取单独的行。

类似于下面的行(尽管这些示例来自文件的开头,但为了方便和提供信息)...

b'BAM\x01\x17\x18\x00\x00@HD\tVN:1.0\tSO:coordinate\n'
b'@SQ\tSN:1\tLN:248956422\n'
b'@SQ\tSN:10\tLN:133797422\n'
b'@SQ\tSN:11\tLN:135086622\n'
b'@SQ\tSN:12\tLN:133275309\n'
b'@SQ\tSN:13\tLN:114364328\n'
b'@SQ\tSN:14\tLN:107043718\n'
b'@SQ\tSN:15\tLN:101991189\n'
b'@SQ\tSN:16\tLN:90338345\n' 
b'@SQ\tSN:17\tLN:83257441\n'
b'@SQ\tSN:18\tLN:80373285\n'

有些人可能会注意到这是一个 BAM 文件,因此如果有更好的方法来执行此操作,欢迎提出建议...尽管 samtools 过滤器无法满足我的需要。我必须按行查找,而不是按数据查找。

您将无法在 gzip 文件中查明随机访问的特定行,但您可以使用压缩文件中的索引,然后查明包含 1000 行或其他内容的块。 indexed-gzip 可能是一个选项。

但是,看着这些数据,我想知道您是否不能仅手动进行压缩。如果将压缩到固定长度,则可以计算每行在文件中的起始位置,然后从该位置读取。似乎每一行只能由两个数字表示。还是我不明白格式?

一个简单的方法是利用有效 gzip 流的串联是 gzip 流这一事实。然后在压缩时,您可以将行块压缩到单独的 gzip 流中,并注意文件中 gzip 流的起始位置,以及该流中压缩的第一行的行号。然后你就可以跳到那个位置并从那里开始解压。如果您的数据块的数量级为兆字节(大约 50,000 行),那么压缩率的降低应该相对较小。然后平均需要解压缩 25,000 行才能到达任何给定行,而不是 750 万行。

如果您无法控制 gzip 文件的创建,并且无法根据需要重新创建它,那么您可以使用 zran.c 中使用的方法为现有 gzip 文件编制索引。您可以指定您希望访问点的距离,它会构建一个索引,允许从每个访问点开始访问。您还需要为您的行开头建立一个索引(就像您对未压缩文件所做的那样),以将那些具有字节偏移量的索引关联到未压缩数据中。