逐行读取80GB .gz文件内容而不解压

3 投票
6 回答
4547 浏览
提问于 2025-04-18 17:25

我有一个80GB的.gz文件(http://storage.googleapis.com/books/ngrams/books/googlebooks-eng-all-3gram-20120701-th.gz),里面包含一个用制表符分隔的文件,那个文件要大得多。我想知道有没有办法逐行读取这个文件的内容,而不需要把80GB的数据全部加载到内存里,或者解压这个文件?我只需要文件中的特定几行(大约10000行),但我没有80GB的内存,也没有超过1TB的存储空间来解压它。

6 个回答

-1

看看这个 zlib 模块,链接在这里:https://docs.python.org/2.7/library/zlib.html#module-zlib

0

如果你想使用Python,可以看看gzip这个模块。它的基本原理和读取普通文本文件是一样的,也就是说,你可以像处理普通文件那样去处理它。

import gzip
gz = gzip.GzipFile('/path/file.gz')
for i in gz:
    print(i)
0

很遗憾,你需要从头开始解压。不过,你不需要一次性把所有内容都读到内存里。根据我记得的,Python的实现方式是把内容读到内存里,但你可以把gzip当作一个外部工具来运行,然后用它的输出作为你读取csv文件的来源。这样做的好处是可以在另一个处理器上并行解压,效率会更高。

5

解压缩是分块进行的,你不需要把所有解压后的数据都放在内存里,就能找到特定的一行。

你可以把 gzip 模块csv 模块 结合起来,一行一行地处理文件:

import gzip
import csv

with gzip.open('googlebooks-eng-all-3gram-20120701-th.gz', 'rb') as fobj:
    reader = csv.reader(fobj, delimiter='\t')
    for row in reader:
        print row

这样你就可以扫描你想要的行;只要你不试图把所有行都存储在一个列表里,而是逐行处理,它就不会占用太多内存。

快速演示:

>>> import gzip
>>> import csv
>>> fobj = gzip.open('/tmp/googlebooks-eng-all-3gram-20120701-th.gz', 'rb')
>>> reader = csv.reader(fobj, delimiter='\t')
>>> print next(reader)
["T'Hooft , _NOUN_", '1937', '1', '1']

我在这里使用了 next() 函数,一次只获取一行数据,但原理和在循环中使用读取器是一样的。

以上方法占用的内存非常少;文件缓冲区和当前要解压的块加起来也就几千字节,再加上 row 列表中的 Python 字符串。

6

你可以使用 zcat 命令把未压缩的内容直接传输给 grep 或者其他你想用的过滤工具,这样就不会占用额外的空间。例如:

zcat bigfile.gz | grep PATTERN_I_NEED > much_smaller_sample

另外,如果你只是想把内容传给 grep,可以使用 zgrep,例如:

zgrep PATTERN_I_NEED bigfile.gz > much_smaller_sample

不过需要注意的是,在某些系统上,zgrep 并不支持 grep 的所有功能。

撰写回答