为什么使用 gzip 重新压缩文件会产生不同的输出?

Why does recompressing a file using gzip produces a different output?

我需要解压缩、编辑然后重新压缩 Minecraft .dat 文件。然而,在重新压缩后,文件发生了显着变化(我这边没有进行任何编辑),这使得游戏无法读取它。

这是我用来解压的代码片段,

import gzip
import shutil
with gzip.open('file_1.dat', 'rb') as f_in:
    with open('file_1.txt', 'wb') as f_out:
        shutil.copyfileobj(f_in, f_out)

这是我用来压缩文件的代码:

with open('file_1.txt', 'rb') as f_in2:
    with gzip.open('file_1_recmp.dat', 'wb') as f_out2:
        shutil.copyfileobj(f_in2, f_out2)

这是before and after files

所以,我做错了什么?

永远不能期望或依赖解压缩和重新压缩会产生相同的结果。不同的压缩代码、同一代码的不同版本或不同的压缩设置都会产生不同的结果。无损压缩器提供的唯一保证是相反的顺序,即如果你压缩然后解压,你得到的正是你开始的。

在您的情况下,问题是是什么让它“对游戏来说不可读”。

更新给定的二进制文件:

前后gzip文件都是有效的,并且具有相同的未压缩数据。

before 和after 的主要区别在于after 的header 在header 中有一个文件名和一些其他信息。我的第一个理论是游戏中的解压缩器不符合标准 gzip headers,并且正在做一些简单和错误的事情,比如跳过前十个字节,期望接下来的是压缩数据。

您可以使用gzip.GzipFile代替gzip.open来控制header的内容,将文件名留空。您还可以将修改时间设置为零,就像在原始 header 中一样。简单示例:

import sys
import gzip
f = open('out.gz', 'wb')
gz = gzip.GzipFile('', 'wb', 9, f, 0.)
gz.write('this is a test')
gz.close()
f.close()

(或 Python 3,gz.write(b'this is a test')。)