【问题标题】:Why does recompressing a file using gzip produces a different output?为什么使用 gzip 重新压缩文件会产生不同的输出?
【发布时间】:2021-04-05 15:30:12
【问题描述】:

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

这是我用来解压的sn-p代码,

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

那么,我做错了什么?

【问题讨论】:

  • 如果输入不同,输出也会不同。这应该不足为奇。
  • 但是输入是一样的(我在重新压缩之前没有编辑文件,我只是解压缩然后再次压缩,看看它是否保持不变)。
  • file_1.dat 是如何产生的?
  • 对不起,如何设置魔术ID?我是使用 gzip 的新手,快速的 Google 搜索并没有产生任何有用的信息。
  • 一个问题是您的压缩文件包含一些原始数据没有的额外可选标头。也不必担心文件完全相同,gzip 格式是标准的,但实现不一定 java 可能不同,但它应该没有问题,因为它遵循相同的标准

标签: python compression gzip


【解决方案1】:

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

在你的情况下,问题是什么使它“对游戏不可读”。

更新给定的二进制文件:

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

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

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

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')。)

【讨论】:

  • 是的,我很确定文件解压后没有错误,decompressed file 的结构与MC wikipage 中描述的结构相匹配。还有here is the file before decompression,这里是output file after recompression。感谢您的回答!
  • 我不是在问您对原始文件的解压是否有效。我在问你是否解压了 recompressed 文件。
  • 您尝试链接的两个文件都被彻底搞砸了。它们与您的十六进制转储无关。您是否尝试打印文件然后复制并粘贴结果?您不能打印二进制数据。
  • 解压缩重新压缩的文件与解压缩原始文件的结果相同。至于 hex 文件,很抱歉发送垃圾数​​据,这里是 the link 到原始文件和重新压缩文件。我希望这次能成功,感谢回答者!
  • 谢谢。那好多了。您最初发布的重新压缩的十六进制转储有问题,因为那里的内容永远不会通过标头来解压缩数据。
猜你喜欢
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-03
  • 2010-09-06
  • 2012-02-28
  • 2020-04-21
  • 1970-01-01
相关资源
最近更新 更多