使用Java API生成JAR文件时两次输出字节不一致的原因排查
动态生成的JAR文件字节内容不一致的原因
我们在通过代码动态构建JAR文件时,发现多次生成的文件HEX信息存在固定位置的差异。为排查问题,简化场景后仅使用Java API和空Manifest测试,代码如下:
public class MyObject { public static void main(String[] args) { System.out.println("START"); MyObject myObject = new MyObject(); myObject.myTest(); System.out.println("END"); return; } protected void myTest() { System.out.println("Inside myTest()"); try { Manifest manifest = new Manifest(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); JarOutputStream jarOutputStream = new JarOutputStream(byteArrayOutputStream, manifest); byteArrayOutputStream.flush(); byteArrayOutputStream.close(); jarOutputStream.flush(); jarOutputStream.close(); OutputStream outputStream = new FileOutputStream("c:\\Downloads\\outputJar1.jar"); outputStream.write(byteArrayOutputStream.toByteArray()); outputStream.flush(); outputStream.close(); } catch (IOException e) {} } }
执行代码生成outputJar1.jar,修改输出路径后再次执行得到outputJar2.jar,理论上两个文件应完全一致,但对比工具显示存在固定位置的字节差异,且每次生成的文件对应位置的十六进制值固定但两次文件间不同。
原因分析
核心问题在于JAR本质是ZIP格式文件,其中每个条目(包括META-INF/MANIFEST.MF)都会存储条目的最后修改时间戳:
- 当你通过
JarOutputStream写入Manifest时,系统会自动为该Manifest条目添加当前系统时间作为最后修改时间 - 两次执行代码的时间不同,这个时间戳字段的字节值会随之变化,而该字段在ZIP/JAR文件中的位置是固定的,因此两次生成的文件会在固定位置出现差异
额外代码问题提示
你的代码存在流关闭顺序错误:应先关闭JarOutputStream,再关闭ByteArrayOutputStream。因为JarOutputStream在关闭时才会将Manifest的完整内容写入底层的ByteArrayOutputStream,当前的关闭顺序可能导致数据不完整(测试场景中未暴露,但属于潜在风险)。另外,catch块直接吞掉异常的做法不建议,建议添加e.printStackTrace()以便排查后续问题。
内容的提问来源于stack exchange,提问作者Unhandled Exception
相关产品推荐
相关产品推荐

