【问题标题】:Size of files compressed with python gzip module is not reduced使用 python gzip 模块压缩的文件大小不会减少
【发布时间】:2018-05-22 18:37:52
【问题描述】:

我编写了一个简单的测试代码,它生成大量整数并使用gzip 模块将它们写入压缩文件。

import gzip
for idx in range(100000):
    with gzip.open('output.gz', 'ab') as f:
        line = (str(idx) + '\n').encode()
        f.write(line)

压缩文件已创建,但当我解压缩时,原始数据实际上要小很多:

$ ls -l
  588890 output
 3288710 output.gz

你能解释一下我在这里做错了什么吗?

【问题讨论】:

  • 您将 100000 个单独的时间附加到 gzip 而不是压缩 100000 个项目。交换with语句和for循环的顺序,文件大小为212863。
  • @IljaEverilä 这有什么不同?我希望每次我附加到压缩文件中时,它都会解压缩,附加数据并再次压缩结果。
  • 它更类似于将 100000 个单独的 gzip 文件连接在一起。他们的标题等将开始计算。使用您最喜欢的十六进制编辑器并查看文件的内容。您应该会看到大量“输出”字符串等。
  • @IljaEverilä 作为一个有趣的旁注:压缩结果大约是 200 kB,但是当我使用 7z 或 tar.xz 方法手动压缩原始数据时,大小会减少到大约 17 kB。我应该寻找比 gzip 更好的模块。

标签: python gzip


【解决方案1】:

附加模式将附加到现有流的假设是错误的。相反,它将一个新流连接到现有的 gzip 文件。解压缩时,它们会像压缩单个文件一样透明地连接起来。但是每个流都包含自己的header and footer,并且这些加起来。检查您的文件会发现

 % hexdump -C output.gz|head -n5
00000000  1f 8b 08 08 2e e7 03 5b  02 ff 6f 75 74 70 75 74  |.......[..output|
00000010  00 33 e0 02 00 12 cd 4a  7e 02 00 00 00 1f 8b 08  |.3.....J~.......|
00000020  08 2e e7 03 5b 02 ff 6f  75 74 70 75 74 00 33 e4  |....[..output.3.|
00000030  02 00 53 fc 51 67 02 00  00 00 1f 8b 08 08 2e e7  |..S.Qg..........|
00000040  03 5b 02 ff 6f 75 74 70  75 74 00 33 e2 02 00 90  |.[..output.3....|

注意魔术数字1f 8b 的重复,它标志着一个新流的开始。

一般来说,在循环中以附加模式重复打开文件通常是个坏主意。而是打开文件一次进行写入并循环写入内容:

with gzip.open('output.gz', 'wb') as f:
    for idx in range(100000):
        line = (str(idx) + '\n').encode()
        f.write(line)

生成的文件约为 200 kiB,而原始文件为 3 MiB。

【讨论】:

  • 我不知道您和我的代码(withfor 语句的简单交换)会导致不同的输出。很有意思。感谢您对代码背后实际发生的事情的深入解释。
最近更新 更多