【问题标题】:gzip fails at writing high amount of data in filegzip 无法在文件中写入大量数据
【发布时间】:2016-03-15 21:08:55
【问题描述】:

我有很大的 gzip 压缩文件。 我编写了一段代码来将这些文件拆分成更小的文件。我可以指定 每个文件的行数。问题是我最近增加了每次拆分的行数 到 16,000,000,当我处理更大的文件时,不会发生拆分。有时文件更小 生产成功,有时生产了一个但重量只有40B或50B,即 失败。我试图通过查看gzip 中提出的内容来发现例外情况 代码。所以我的代码如下所示:

def writeGzipFile(file_name, content):
    import gzip
    with gzip.open(file_name, 'wb') as f:
        if not content == '':
            try:
                f.write(content)
            except IOError as ioe:
                print "I/O ERROR wb", ioe.message
            except ValueError as ve:
                print "VALUE ERROR wb: ", ve.message
            except EOFError as eofe:
                print "EOF ERROR wb: ", eofe.message
            except:
                print "UNEXPECTED ERROR wb"

问题是内容太高的时候,和行数有关,我经常得到 “意外错误”消息。所以我不知道这里抛出了哪种错误。

我终于发现行数是问题所在,python 的gzip 似乎无法一次将这么多的数据写入一个文件。将每个拆分的行数降低到 4,000,000 个作品。但是,我想拆分内容并按顺序写入文件,以确保即使是高数据内容也能被写入。

所以我想知道如何找出可以使用gzip 一次性写入文件的最大字符数,而不会出现任何故障。


编辑 1

所以我发现了所有剩余的异常(我不知道可以简单地捕获 Exception 抱歉):

def writeGzipFile(file_name, content, file_permission=None):
    import gzip, traceback
    with gzip.open(file_name, 'wb') as f:
        if not content == '':
            try:
                f.write(content)
            except IOError as ioe:
                print "I/O ERROR wb", ioe.message
            except ValueError as ve:
                print "VALUE ERROR wb: ", ve.message
            except EOFError as eofe:
                print "EOF ERROR wb: ", eofe.message
            except Exception, err:
                print "EXCEPTION:", err.message
                print "TRACEBACK_1:", traceback.print_exc(file=sys.stdout)
            except:
                print "UNEXPECTED ERROR wb"

错误大约是int 大小。我从没想过有一天我会超过 int 大小:

EXCEPTION: size does not fit in an int
TRACEBACK_1:Traceback (most recent call last):
  File "/home/anadin/dev/illumina-project-restructor_mass-splitting/illumina-project-restructor/tools/file_utils/file_compression.py", line 131, in writeGzipFile
    f.write(content)
  File "/usr/local/cluster/python2.7/lib/python2.7/gzip.py", line 230, in write
    self.crc = zlib.crc32(data, self.crc) & 0xffffffffL
OverflowError: size does not fit in an int
None

好的,所以 int 的最大大小为 2,147,483,647,根据我的日志,我的数据块约为 3,854,674,090。这个块是一个字符串,我对其应用了__len__() 函数。

因此,正如我计划的那样,正如 Antti Haapala 所建议的那样,我将一次读取较小的块,以便按顺序将它们写入较小的文件。

【问题讨论】:

  • Ans 当你解决了这个问题 - 不要使用未命名的异常块 - 因为它们通过隐藏故障机制而导致这类问题。 (除非您真的不在乎操作是否失败)。
  • 如果它在您减少正在处理的数据量时有效,那么我很确定问题在于您将 所有 数据保存在单个字符串:content。这可能会耗尽你所有的内存。我看不到您的其余代码,但通常您想读取一小块数据(通常是一行),随心所欲地处理它,然后将其提供给 gzip,然后将那一小块写入磁盘.然后,您重复这 1600 万次(或经常),并且占用的内存绝不会超过一行...
  • FWIW, this answer 我几年前写的展示了如何逐块压缩文件。

标签: python python-2.7 gzip


【解决方案1】:

无论如何,我怀疑原因是某种内存不足错误。我很不清楚你为什么不一次少写一些数据;这里使用chunks方法from this answer

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in xrange(0, len(l), n):
        yield l[i:i+n]

...
with gzip.open(file_name, 'wb') as f:
    for chunk in chunks(content, 65536):
        f.write(chunk)

也就是说,你就像吃大象一样,一次咬一口。

【讨论】:

  • 谢谢我的问题有点复杂,但原则是一次真正写更小的块。顺便说一句,你为什么将块限制为 65536?在这里,我受到 int 大小的限制。我可以用 int 范围替换你的尺寸吗?或者更有效的方法,你的看法是什么?
  • 我还是不会碰运气!你会很快耗尽内存。这种拼接实际上复制字符串的那一部分。
  • @kaligne:64k 是一个很好的块大小。您可能通过更大的块大小获得稍快的性能,具体取决于您的硬件,但 IME 的改进非常有限,而且我已经在一系列驱动器上进行了测试,包括机械和固态驱动器。请记住,您不是直接与硬件交互,而是通过使用高效磁盘缓冲的操作系统驱动程序软件,并且驱动器也有自己的板载缓存。
  • 您可以使用 1 兆字节...或 16... 但不是 int 范围。 (它也可以是 64 位的!)
  • @Antti Haapala:呵呵,说得好……最重要的是,你刚刚教会了我 xrange 的用处!
猜你喜欢
  • 2012-12-22
  • 2015-02-07
  • 2017-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-27
相关资源
最近更新 更多