代码之家  ›  专栏  ›  技术社区  ›  Chris B.

在Python中压缩编解码器是如何工作的?

  •  8
  • Chris B.  · 技术社区  · 14 年前

    我使用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))
    

    但是,我的输出文件的大小是1409780。跑步 bunzip2 bzip2 结果是217275个。换句话说,未压缩的文件比使用Python的bzip编解码器压缩的文件小得多。 除了跑步,还有别的方法可以解决这个问题吗 在命令行上?

    我尝试了Python的gzip编解码器(将行改为 codecs.open(archive_file, 'a+', 'zip') )看看它是否解决了这个问题。我仍然得到大文件,但我也得到一个 gzip: archive_file: not in gzip format 尝试解压缩文件时出错。 怎么回事?


    :我最初是以附加模式而不是写入模式打开文件的。虽然这可能是问题,也可能不是问题,但如果文件是以“w”模式打开的,问题仍然存在。

    4 回复  |  直到 14 年前
        1
  •  2
  •   Uli Köhler    11 年前

    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本身无法处理它(尽管有 is a patch 为了它)。如果需要将创建的压缩文件读回Python,请坚持每个文件使用一个流。

        2
  •  1
  •   cobbal    14 年前

    write() . 这将导致每一行在其自己的bzip块中被压缩。

    在将其写入文件之前,我会尝试在内存中构建一个更大的字符串(如果担心性能的话,也可以是字符串列表)。一个好的大小拍摄将是900K(或更多),因为这是块大小bzip2使用

        3
  •  0
  •   DNS    14 年前

    >>> 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")
    

    >>>>>f.读取()
    'ABCD'
    

    我想bunzip2也在做同样的事情。所以实际上你的文件是压缩的,比它包含的数据小得多。但是当您通过bunzip2运行它时,只会返回您写入它的第一组记录;其余的记录将被丢弃。

        4
  •  0
  •   guidoism    14 年前

    我不确定这与编解码器的方式有多大区别,但是如果您使用gzip模块中的GzipFile,您可以以增量方式附加到该文件,但它不会很好地压缩,除非您一次写入大量数据(可能大于1 KB)。这就是压缩算法的本质。如果您正在写入的数据不是非常重要(即,如果您的进程死亡,您可以处理丢失数据的问题),那么您可以编写一个缓冲GzipFile类来包装导入的类,该类将写出更大的数据块。