【问题标题】:Determining GZIPOutputStream behavior确定 GZIPOutputStream 行为
【发布时间】:2020-02-16 10:33:58
【问题描述】:

以下代码为两个字符串生成确定性(shasum 相同)的文件。

    try(
            FileOutputStream fos = new FileOutputStream(saveLocation);
            GZIPOutputStream zip = new GZIPOutputStream(fos, GZIP_BUFFER_SIZE);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zip, StandardCharsets.UTF_8));
            ){
        writer.append(str);
    }

生产:

a.gz f0200d53f7f9b35647b5dece0146d72cd1c17949

但是,如果我在命令行上获取文件并重新压缩它,它会产生不同的结果

> gunzip -n a.gz ;gzip -n a ; shasum a.gz 

50f478a9ceb292a2d14f1460d7c584b7a856e4d9  a.gz

如何使用 /usr/bin/gzip 和 gunzip 使其与原始 sha 匹配?

【问题讨论】:

  • 文件大小如何,是否匹配?
  • 您必须匹配 compression level 并且您可能需要匹配缓冲区大小(我不能 100% 确定第二点)。
  • 尝试将-1-9 添加到gzip 命令,看看是否有任何改变。
  • 我检查了压缩级别,但这在任何级别上都不起作用。文件大小匹配良好。
  • @ergonaut 请提供其余代码(例如,str 的来源)。

标签: java sha gzipoutputstream


【解决方案1】:

我认为问题很可能是Gzip文件头。

  • Gzip 格式规定在文件头中包含文件名和文件时间戳。 (我看到你在解压缩和重新压缩时使用-n...这在这里可能是正确的。)

  • Gzip 格式还在标题中包含“操作系统 ID”。这应该识别源文件系统类型;例如0 代表 FAT,3 代表 UNIX,依此类推。

其中任何一个都可能导致 Gzip 文件不同,从而导致哈希值不同。

如果我要自己解决这个问题,我会先使用cmp 查看压缩文件差异的开始位置,然后使用od 确定差异所在。请参阅 Gzip 文件格式规范以了解差异的含义:

  • RFC 1952 - GZIP 文件格式规范版本 4.3
  • 维基百科的gzip 页面。

如何使用gzipgunzip 使其与原始SHA 匹配?

假设区别在于操作系统 ID,我认为没有实用的方法可以使用 gzipgunzip 命令解决此问题。


我查看了 Java 11 中 GZIPOutputStream 的源代码,它并不乐观。

  • 将时间戳硬连接为零。
  • 它将操作系统标识符硬连接为零(这应该意味着 FAT)。

硬连线在private 方法中,几乎不可能通过子类化或反射来“修复”。您可以复制代码并以这种方式修复它,但是您必须无限期地维护您的变体 GZIPOutputStream 类。

(我会考虑更改应用程序......或其他任何东西......这样我就不需要校验和相同。你没有说你为什么这样做。它仅用于测试目的,尝试寻找不同的方法来实现测试。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2018-02-12
    • 2015-12-29
    • 1970-01-01
    相关资源
    最近更新 更多