我有一个80GB的 .gz 文件(http://storage.googleapis.com/books/ngrams/books/googlebooks-eng-all-3gram-20120701-th.gz),其中包含一个分隔符文件,而这个文件更大。是否有一种方法可以逐行复制该文件的内容,而不需要将80GB加载到内存中或解压缩该文件?
该文件中有特定的几行(约10000行)是我需要的,但我没有80GB以上的RAM或1TB以上的存储空间来解压缩它。
zcat
来将未压缩的内容流式传输到grep
或任何你想要的过滤器中,而不会产生空间开销。例如:zcat bigfile.gz | grep PATTERN_I_NEED > much_smaller_sample
zgrep
,例如:zgrep PATTERN_I_NEED bigfile.gz > much_smaller_sample
但是在某些系统上,zgrep
并不支持 grep
的全部功能。
解压缩是分块进行的,你不需要将所有解压缩后的数据都存储在内存中才能访问特定行。
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 字符串。很不幸,你需要从头开始解压缩。然而,你不需要一次性将所有内容读入内存。据我记得,Python的实现是将内容读入内存的,但你可以作为外部工具运行gzip,并将其stdout作为csv读取器的数据源。这样做的好处是可以在单独的处理器中并行解压缩。
import gzip
gz = gzip.GzipFile('/path/file.gz')
for i in gz:
print(i)
这是我过去使用过的
BUFF_SIZE = 120000
with open(src, 'rb') as src, open(dst, 'wb') as fdst:
# prevent loading too much data to memory
for n,x in enumerate(iter(lambda: src.read(BUFF_SIZE),"")):
fdst.write(x)
显然,这将一个文件的内容复制到另一个文件中,似乎比类似实现更快。您可以更改缓冲区大小以加载到内存中的任何大小。