我正在查询数据库并使用Python归档结果,并且我正在尝试在将数据写入日志文件时压缩数据。不过,我有一些问题。

我的代码看起来像这样:

log_file = codecs.open(archive_file, 'w', 'bz2')
for id, f1, f2, f3 in cursor:
    log_file.write('%s %s %s %s\n' % (id, f1 or 'NULL', f2 or 'NULL', f3))

但是,我的输出文件的大小为1,409,780。跑步 bunzip2 在文件上导致大小为943,634的文件,并运行 bzip2 因此,大小为217,275。换句话说,未压缩文件明显小于使用Python的BZIP编解码器压缩的文件。 除了运行以外,有没有办法解决此问题 bzip2 在命令行上?

我尝试了Python的GZIP编解码器(将行更改为 codecs.open(archive_file, 'a+', 'zip'))查看是否解决了问题。我仍然收到大文件,但我也得到了一个 gzip: archive_file: not in gzip format 当我尝试解压缩文件时,错误。 那里发生了什么?


编辑: :我最初以附加模式打开文件,而不是写模式。尽管这可能是一个问题,也可能不是问题,但如果文件在“ W”模式下打开,则问题仍然存在。

有帮助吗?

解决方案

正如其他海报所指出的那样,问题是 codecs 库不使用增量编码器来编码数据。相反,它将馈送到的每个数据段编码为 write 方法作为压缩块。这是可怕的效率,对于旨在与溪流合作的图书馆来说,这是一个可怕的设计决定。

具有讽刺意味的是,Python中已经内置了一个完全合理的增量BZ2编码器。创建一个“类似文件”的类并不困难,该类可以自动执行正确的操作。

import bz2

class BZ2StreamEncoder(object):
    def __init__(self, filename, mode):
        self.log_file = open(filename, mode)
        self.encoder = bz2.BZ2Compressor()

    def write(self, data):
        self.log_file.write(self.encoder.compress(data))

    def flush(self):
        self.log_file.write(self.encoder.flush())
        self.log_file.flush()

    def close(self):
        self.flush()
        self.log_file.close()

log_file = BZ2StreamEncoder(archive_file, 'ab')

警告: :在此示例中,我以附加模式打开了文件;将多个压缩流附加到单个文件中非常有效 bunzip2, ,但是Python本身无法应付(尽管那里 是一个补丁 为了它)。如果您需要读取您创建回Python的压缩文件,请坚持每个文件的单个流。

其他提示

问题似乎是在每一个上都写出输出 write(). 。这会导致每行在自己的BZIP块中被压缩。

在将其写入文件之前,我将尝试在内存中构建更大的字符串(如果您担心性能,则为字符串列表)。可以拍摄的好尺寸将为90万(或更多),因为这是BZIP2使用的块大小

问题是由于您使用附录模式,这导致了包含多个压缩数据块的文件。看看这个示例:

>>> import codecs
>>> with codecs.open("myfile.zip", "a+", "zip") as f:
>>>     f.write("ABCD")

在我的系统上,这会产生一个文件12字节的大小。让我们看看它包含的内容:

>>> with codecs.open("myfile.zip", "r", "zip") as f:
>>>     f.read()
'ABCD'

好的,现在让我们在附录模式下进行另一个写作:

>>> with codecs.open("myfile.zip", "a+", "zip") as f:
>>>     f.write("EFGH")

该文件现在大小为24个字节,其内容为:

>>> with codecs.open("myfile.zip", "r", "zip") as f:
>>>     f.read()
'ABCD'

这里发生的事情是Unzip期望单个拉链流。您必须检查规格,以查看多个串联流的官方行为是什么,但是根据我的经验,他们处理第一个并忽略其余数据。那就是Python所做的。

我希望Bunzip2正在做同样的事情。因此,实际上,您的文件被压缩了,并且比包含的数据小得多。但是,当您通过BUNZIP2运行它时,您只会恢复您写给它的第一组记录;其余的被丢弃。

我不确定这与编解码器的方式有何不同,但是如果您使用GZIPFILE从GZIP模块中使用GZIPFILE,则可以逐步附加到文件上,但是除非您在一个人写大量数据,否则它不会很好地压缩时间(可能> 1 kb)。这只是压缩算法的本质。如果您正在编写的数据并不重要(即,如果您的流程死亡,可以处理丢失),那么您可以编写一个缓冲的Gzipfile类包装列出大量数据的导入类。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top