Zip / Jar文件中的二进制差异

时间:2009-04-15 20:32:47

标签: java jar zip

似乎从完全相同的源文件构建jar或zip将始终产生不同的文件。我尝试使用java jar命令和ant。中的jar和zip任务。

这似乎是由于新的jar / zips将时间戳设置为每个存储文件的当前时间。

有没有办法强制拉链工具只使用文件系统上文件的时间戳,以确保从完全相同的源构建的jar看起来完全一样?

8 个答案:

答案 0 :(得分:3)

二进制差异是由于清单文件的时间戳。 如果你让jar自己创建一个清单,它将创建一个清单 飞行并将创建的清单设置为currentTimeMillis。

你可以通过以下方式解决:
1.不要添加清单(如果使用蚂蚁,则必须使用拉链而不是罐子) 2.像添加普通文件一样添加清单。 (因此清单是文件系统上的文件,并不是即时创建的)

答案 1 :(得分:2)

使用Java java.util.zip.ZipOutputStream标准库实用程序,可以创建具有可复制内容的zip文件。

唯一的技巧是必须使用以下技巧固定zip条目的时间戳:

ZipOutputStream zos=...;
ZipEntry ze=new ZipEntry("Filename");
zipEntry.setTime(0);
zos.putNextEntry(ze);
try
{
   zos.write(data);
}finally
{
  zos.closeEntry();
}

答案 2 :(得分:1)

我认为没有办法让zip做到这一点,但是你肯定可以将文件系统上的文件的时间戳打到已知的日期(使用unix下的'touch'命令 - 我不知道在Windows下的内容)在你创建jar之前。

答案 3 :(得分:1)

我有类似的问题,正如pjz建议的那样,我通过'触摸'文件解决了它,然后将它们添加到jar中(因此,它对我有用:-))。如果需要,你可以在GNU Windows Utilities,核心工具:http://gnuwin32.sourceforge.net/packages/coreutils.htm中找到适用于Windows的触摸,但它只是这个单一的一个大包(尽管你可能还有许多其他有用的实用工具) ),或者,下载类似http://www.softpedia.com/progClean/Touch-for-Windows-Clean-41086.html的内容。

答案 4 :(得分:1)

好的,我和同事想出了一个适合我们的解决方案。

我们不使用重新设计整个构建过程来删除任何类或jar文件,而是使用以下过程:

  1. 构建新工件。
  2. 使用jardiff(jnlp的一部分)来比较之前版本的更改。
  3. 如果jardiff生成的diff jar没有变化,请从之前的构建中获取工件。
  4. 是的,我知道这听起来很糟糕,但它肯定会重写构建脚本以考虑到这一点。此外,我们可以在新机器上进行完全干净的构建(在服务器发生故障的情况下),此过程将确保仅生成实际更新的jar。

答案 5 :(得分:0)

此答案不足。阅读我的其他答案。我尚未删除此答案,因为它显示了非二进制兼容性的某些原因,但并非所有原因。

我有一个详尽的答案,但不幸的是用德语:https://www.vishia.org/SwEng/pdf/GenerateRepeatability_de.pdf 简短演示:

echo compile javac
$JAVAC_HOME/bin/javac -d $TMPJAVAC/binjar -cp $CLASSPATH -sourcepath $SRCPATH $FILE1SRC 
mkdir $TMPJAVAC/binjar/META-INF
##Note: create the manifest file manually, not with jar, because of time stamp
cp $MANIFEST $TMPJAVAC/binjar/META-INF/MANIFEST.MF  
echo touch timestams to $VERSION
find $TMPJAVAC/binjar -exec touch -d $VERSION {} \;
echo build jar
$JAVAC_HOME/bin/jar -cvfM $JARFILE -C $TMPJAVAC/binjar . > $TMPJAVAC/jar.txt
if ! test "$MD5FILE" = ""; then echo output MD5 checksum
  md5sum -b $JARFILE > $MD5FILE
fi  
echo ok $JARFILE

这是一个通用的shell脚本,由外部设置的脚本变量控制。 可以从另一个shell脚本或gradle中调用它。 必不可少的是清单的touch命令和复制命令,以及jar的M选项(不是m)。 jar文件的二进制差异来自所包含文件的时间戳。 Hartmut Schorrig

答案 6 :(得分:0)

不幸的是,我从2020-03-17开始的回答在所有情况下都不会产生可复制的jar文件(二进制兼容)。原因:jar中文件的顺序取决于随机性。我使用Windows和Linux在另一个机器上生成,在jar / zip文件中产生另一个文件顺序,这导致了另一个二进制内容。如果将jar文件逐文件进行比较(解压缩后),则它们是相同的。但是纯二进制jar并非如此。 我有一个解决方案,它不使用来自JDK的jar命令,而是一个使用JRE功能的自己的jar算法。 JRE包含java.util.jar。*和java.util.zip。*作为标准。可以阅读https://vishia.org/Java/html5/source+build/reproducibleJar.html中的描述。您可以下载具有给定的MD5校验和的小型https://www.vishia.org/Java/Download/versionArchive/vishiaZipJar-2020-03-23.jar(请访问此Download / versionArchive页面)。本文包含示例。 我已经在Windows和Linux上进行了测试,它们使用了不同的JDK版本,结果是二进制兼容的。

答案 7 :(得分:0)

首先,使用gradle构建系统的任何人都可以廉价/轻松地获得二进制稳定的jar:

tasks.withType(Jar).configureEach {
    Jar jar ->
        jar.preserveFileTimestamps = false
        jar.reproducibleFileOrder = true
}

这完成了其他答案的建议:确保时间戳稳定,并确保jar中条目的顺序也稳定。我相信这里的大脑不在jar命令本身的范围内,但是我对此问题的投入不足以进行检查。