Java 确定GZIPOutputStream行为
下面的代码为两个字符串生成确定性文件(shasum相同)Java 确定GZIPOutputStream行为,java,sha,gzipoutputstream,Java,Sha,Gzipoutputstream,下面的代码为两个字符串生成确定性文件(shasum相同) try( FileOutputStream fos = new FileOutputStream(saveLocation); GZIPOutputStream zip = new GZIPOutputStream(fos, GZIP_BUFFER_SIZE); BufferedWriter writer = new BufferedWriter(new Ou
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匹配?我认为问题可能是gzip文件头
- Gzip格式提供了在文件头中包含文件名和文件时间戳的功能。(我看到您在解压缩和重新压缩时使用了
,这在这里可能是正确的。)-n
- Gzip格式在标题中还包含一个“操作系统id”。这是为了识别源文件系统类型;e、 0代表FAT,3代表UNIX,等等
cmp
查看压缩文件差异的起始位置,然后使用od
确定差异是什么。请参阅Gzip文件格式规范,了解差异的含义:
- -GZIP文件格式规范版本4.3
- 维基百科的页面
gzip
和gunzip
使其与原始SHA匹配
假设区别在于操作系统id,我认为没有一种实用的方法可以通过gzip
和gunzip
命令来解决这个问题
我查看了Java11中的
GZIPOutputStream
的源代码,但这并不乐观
- 将时间戳硬连接到零
- 它将操作系统标识符硬连接到零(这应该意味着FAT)
私有方法中,几乎不可能通过子类化或反射来“修复”。您可以复制代码并以这种方式修复它,但是您必须无限期地维护variantGZIPOutputStream
类
(我会考虑更改应用程序…或其他任何东西…这样我就不需要校验和相同。您还没有说明为什么要这样做。这只是出于测试目的,请尝试寻找不同的方法来实现测试。)文件大小如何,它匹配吗?您必须匹配,并且可能需要匹配缓冲区大小(在第二点上我不是100%确定)。尝试将-1
或-9
添加到gzip
命令中,看看这是否会改变任何内容。我检查了压缩级别,但在任何级别上都不起作用。文件大小匹配得很好。@ergonaut请提供其余代码(例如,str
来自何处)。