我使用以下简单的Python脚本来压缩EC2 m3.large实例上的一个大文本文件(例如,10GB)。但是,我总是得到一个MemoryError
:
import gzip
with open('test_large.csv', 'rb') as f_in:
with gzip.open('test_out.csv.gz', 'wb') as f_out:
f_out.writelines(f_in)
# or the following:
# for line in f_in:
# f_out.write(line)
我得到的线索是:
Traceback (most recent call last):
File "test.py", line 8, in <module>
f_out.writelines(f_in)
MemoryError
我读过一些关于这个问题的讨论,但仍然不太清楚如何处理这个问题。有人能给我一个更容易理解的答案吗?
即使逐行读取文件,也会出现内存错误。我想是因为你没有多少可用内存和很大的行。然后应使用二进制读取:
真奇怪。如果您试图压缩一个不包含许多换行符的大型二进制文件,我会预料到这个错误,因为这样的文件可能包含一个对RAM来说太大的“行”,但它不应该出现在一个行结构的.csv文件上。
但是无论如何,逐行压缩文件不是很有效。即使操作系统缓冲磁盘I/O,但读取和写入更大的数据块(如64KB)通常要快得多。
我在这台机器上有2GB的RAM,我刚刚成功地用下面的程序压缩了一个2.8GB的tar文件。
我正在运行Python 2.6.6,
gzip.open()
不支持with
。正如Andrew Bay在注释中所指出的,
if block == '':
在Python 3中无法正常工作,因为block
包含字节,而不是字符串,并且空字节对象与空文本字符串不相等。我们可以检查块的长度,或者与b''
(这在Python 2.6+中也适用)进行比较,但是简单的方法是if not block:
。这里的问题与gzip无关,与逐行读取10GB文件(其中没有新行)有关:
这将为您提供一个完全由0字节组成的10GB稀疏文件。意思是没有换行字节。意思是第一行是10GB长。这意味着读取第一行需要10GB。(如果您使用的是3.3之前版本的Python并试图将其读取为Unicode,甚至可能是20或40GB)
如果要复制二进制数据,不要逐行复制。无论是一个普通的文件,一个正在为您动态解压缩的
GzipFile
,一个socket.makefile()
,或者其他什么,您都会遇到同样的问题。解决方案是逐块复制。或者只使用^{} ,这会自动为您实现。
默认情况下,
copyfileobj
使用优化后的块大小,通常非常好,而不是非常坏。在这种情况下,您可能需要更小的大小,或者更大的大小;很难预测哪个是先验的。*因此,通过使用timeit
和不同的bufsize
参数(例如,从1KB到8MB的4次方幂)到copyfileobj
来测试它。但是默认的16KB可能已经足够好了,除非你做了很多这方面的工作。*如果缓冲区太大,可能会导致长I/O块和长处理块交替出现。如果太小,则可能需要多次读取才能填满一个gzip块。
相关问题 更多 >
编程相关推荐