我正在尝试使用python的gzip包来执行拉链和重新压缩gzip'd存档(或任何二进制数据)的测试,以更好地理解GNU gzip版本和Python的gzip.GzipFile之间的实现差异。用例是我想检查压缩文件的内容并重新压缩它而不改变输出。
我注意到的一个差异是,在压缩具有两个不同gzip版本的文件时,输出是相同的;但是,当使用gzip.GzipFile压缩它时,输出会发生变化。
例如......
这里,lzo-2.09.tar.gz已经使用一个版本的gzip进行了压缩,我正在使用另一个版本对其进行压缩。
joga:/tmp/gztest$ ls -l lzo*
-rw-r--r--@ 1 joga wheel 594855 Dec 25 14:31 lzo-2.09.tar.gz
-rw-r--r--@ 1 joga wheel 594855 Dec 25 14:38 lzo-2.09_copy.tar.gz
joga:/tmp/gztest$ gunzip lzo-2.09_copy.tar.gz
joga:/tmp/gztest$ cat lzo-2.09_copy.tar |gzip -9 >lzo-2.09_copy.tar.gz
joga:/tmp/gztest$ ls -l lzo*
-rw-r--r--@ 1 joga wheel 594855 Dec 25 14:31 lzo-2.09.tar.gz
-rw-r--r-- 1 joga wheel 594855 Dec 25 14:39 lzo-2.09_copy.tar.gz
我们看到输出是相同的(时间戳除外)。这是相应的python脚本:
import gzip
from StringIO import StringIO
with gzip.open('lzo-2.09.tar.gz', 'rb') as fh:
lzo_bin = fh.read()
gzip_io = StringIO()
compressed_gzip = gzip.GzipFile(fileobj=gzip_io, mode='wb', compresslevel=9)
with compressed_gzip as gzip_handle:
gzip_handle.write(lzo_bin)
with open('lzo_py.tar.gz', 'wb') as fh:
fh.write(gzip_io.getvalue())
我们看到结果不同:
joga:/tmp/gztest$ ls -l lzo*
-rw-r--r--@ 1 joga wheel 594855 Dec 25 14:31 lzo-2.09.tar.gz
-rw-r--r-- 1 joga wheel 594855 Dec 25 14:39 lzo-2.09_copy.tar.gz
-rw-r--r-- 1 joga wheel 595135 Dec 25 14:43 lzo_py.tar.gz
以下是两个重新压缩文件中的前几个字节:
GNU Gzip:
00000000 1F 8B 08 00 00 00 00 00 02 FF 54 B7 63 8C 26 4C D8 A6 DD B6 ..........T.c.&L....
Python GzipFile
00000000 1F 8B 08 00 00 00 00 00 02 FF EC 7D 7B 7B DB B6 F5 F0 EF DF ...........}{{......
据我所知,gzip / zlib不保证同一文件的两个副本在使用不同的软件包版本压缩时会产生相同的结果。然而,根据经验,我观察到很多情况都是如此。
我的问题是 - 可能导致这种差异的Python实现有什么不同?我查看了源代码并且自己找不到它,虽然我没有压缩技术或实现的背景知识。
答案 0 :(得分:2)
Python正在使用zlib,它具有与gzip不同的压缩代码,尽管它是由同一个人编写的,zlib代码来自旧的gzip代码。结果通常不同。
但是,正如您所注意到的,不能保证也不需要不同的压缩器能够从相同的未压缩输入产生相同的输出。确保所有这一切以及所有需要确保的是,当再次解压缩时,两者都产生完全原始的未压缩输入。这是无损的定义。
那么压缩数据有什么不同呢?你为什么关心?