巩义网站建设费用多少,手机优化管家,网站建设优化一体,乐清定制网站建设电话spring boot jar 启动报错 Zip64 archives are not supported 原因、解决方案问题为什么 spring boot 不支持 zip64zip、zip64 功能上的区别zip 的文件格式spring-boot-loader 是如何判断是否是 zip64 的#xff1f; 参考 spring boot 版本是 2.1.8.RELEASE#xff0c;引入以… spring boot jar 启动报错 Zip64 archives are not supported 原因、解决方案问题为什么 spring boot 不支持 zip64zip、zip64 功能上的区别zip 的文件格式spring-boot-loader 是如何判断是否是 zip64 的 参考 spring boot 版本是 2.1.8.RELEASE引入以下 phoenix 依赖之后启动报错。
dependencygroupIdorg.apache.phoenix/groupIdartifactIdphoenix-client-hbase-2.4/artifactIdversion5.1.3/version
/dependency错误日志
PS D:\project\java\zip64\target java -jar .\zip64-0.0.1-SNAPSHOT.jar
Exception in thread main java.lang.IllegalStateException: Failed to get nested archive for entry BOOT-INF/lib/phoenix-client-hbase-2.4-5.1.3.jarat org.springframework.boot.loader.archive.JarFileArchive.getNestedArchive(JarFileArchive.java:108)at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchives(JarFileArchive.java:87)at org.springframework.boot.loader.ExecutableArchiveLauncher.getClassPathArchives(ExecutableArchiveLauncher.java:69)at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
Caused by: java.io.IOException: Unable to open nested jar file BOOT-INF/lib/phoenix-client-hbase-2.4-5.1.3.jarat org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:258)at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:244)at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchive(JarFileArchive.java:104)... 4 more
Caused by: java.lang.IllegalStateException: Zip64 archives are not supportedat org.springframework.boot.loader.jar.CentralDirectoryEndRecord.getNumberOfRecords(CentralDirectoryEndRecord.java:121)at org.springframework.boot.loader.jar.JarFileEntries.visitStart(JarFileEntries.java:117)at org.springframework.boot.loader.jar.CentralDirectoryParser.visitStart(CentralDirectoryParser.java:85)at org.springframework.boot.loader.jar.CentralDirectoryParser.parse(CentralDirectoryParser.java:56)at org.springframework.boot.loader.jar.JarFile.init(JarFile.java:125)at org.springframework.boot.loader.jar.JarFile.init(JarFile.java:112)at org.springframework.boot.loader.jar.JarFile.createJarFileFromFileEntry(JarFile.java:289)at org.springframework.boot.loader.jar.JarFile.createJarFileFromEntry(JarFile.java:266)at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:255)原因、解决方案
Google 很快就找到了原因stackoverflow 上有类似的问题 java - Add more than 65535 entries jar in Spring boot - Stack Overflow。
第一个回答给出了原因spring boot 不支持一个 jar 文件中多于 65534这里应该写错了应该是 65535 个文件并附上了抛异常的代码。
第二个回答是 spring boot 的 issues有兴趣的可以自己看一下 Support zip64 format executable archives · Issue #2895 · spring-projects/spring-boot (github.com)
第三个回答给出了解决办法升级到 2.2.x也给出了支持 zip64 的提交记录 Support zip64 jars by cvienot · Pull Request #16091 · spring-projects/spring-boot (github.com)。我升级成 2.2.0.RELEASE 确实解决了问题。 问题
回答一中的代码来自 spring-boot-loader 子项目中的 org.springframework.boot.loader.jar.CentralDirectoryEndRecord#getNumberOfRecords 方法依赖如下
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-loader/artifactIdversion2.1.8.RELEASE/version
/dependency为什么 spring boot 不支持 zip64
从 ZIP (file format) - Wikipedia 中可以看出 zip、zip64 在文件的格式上是不同的。猜测应该是开发者没想到 jar 包里的文件个数或 jar 包的大小会超过 65535所以没有实现 zip64 相关的。从以下提交中能看出一二。直到最后的两个提交才有人实现了 zip64 的相关代码。 zip、zip64 功能上的区别 zip64 格式是标准 zip 格式的扩展实际上消除了 zip 存档中文件大小和数量的限制。 每种格式允许的最大值总结如下 Standard FormatZip64 FormatNumber of Files Inside an Archive65,5352^64 - 1Size of a File Inside an Archive [bytes]4,294,967,2952^64 - 1Size of an Archive [bytes]4,294,967,2952^64 - 1Number of Segments in a Segmented Archive999 (spanning) 65,535 (splitting)4,294,967,295 - 1Central Directory Size [bytes]4,294,967,2952^64 - 1 zip 的文件格式 zip格式压缩包主要由三大部分组成数据区、中央目录记录区也有叫核心目录记录、中央目录记录尾部区。 数据区是由一系列本地文件记录组成本地文件记录主要是记录了压缩前后文件的元数据以及存放压缩后的文件。 中央目录记录区是有一系列中央目录记录所组成一条中央目录记录对应数据区中的一个压缩文件记录。 中央目录记录尾部(End of central directory record)主要作用是用来定位中央目录记录区的开始位置同时记录压缩包的注释内容。 End of central directory record (EOCD)
OffsetBytesDescription[33]中文04End of central directory signature 0x06054b50签名42Number of this disk (or 0xffff for ZIP64)62Disk where central directory starts (or 0xffff for ZIP64)82Number of central directory records on this disk (or 0xffff for ZIP64)102Total number of central directory records (or 0xffff for ZIP64)文件数量ZIP64 为 0xffff 124Size of central directory (bytes) (or 0xffffffff for ZIP64)164Offset of start of central directory, relative to start of archive (or 0xffffffff for ZIP64)202Comment length (n)注释长度22nComment
spring-boot-loader 是如何判断是否是 zip64 的
// 从 bytes 的 offset 偏移量开始以小端模式读取 length 个字节
public static long littleEndianValue(byte[] bytes, int offset, int length) {long value 0;for (int i length - 1; i 0; i--) {value ((value 8) | (bytes[offset i] 0xFF));}return value;
}/*** A ZIP File End of central directory record (EOCD).** author Phillip Webb* author Andy Wilkinson* see a hrefhttps://en.wikipedia.org/wiki/Zip_%28file_format%29Zip File Format/a*/
class CentralDirectoryEndRecord {// EOCD 最小长度从表中可以看出在没有注释的情况下是 22private static final int MINIMUM_SIZE 22;// 从表中可以看出注释长度为 2 字节所有最大值是 65535private static final int MAXIMUM_COMMENT_LENGTH 0xFFFF;private static final int MAXIMUM_SIZE MINIMUM_SIZE MAXIMUM_COMMENT_LENGTH;// EOCD 开始的标记private static final int SIGNATURE 0x06054b50;// EOCD 中“注释长度”字段的偏移量从表中可以看出是 20private static final int COMMENT_LENGTH_OFFSET 20;// 每次从文件尾部读取 256 字节private static final int READ_BLOCK_SIZE 256;// 最终是 EOCD 的字节数组private byte[] block;// EOCD 在 block 中的偏移量private int offset;// EOCD 的字节数private int size;/*** Create a new {link CentralDirectoryEndRecord} instance from the specified* {link RandomAccessData}, searching backwards from the end until a valid block is* located.* param data the source data* throws IOException in case of I/O errors*/CentralDirectoryEndRecord(RandomAccessData data) throws IOException {// 从文件尾部读取 256 字节this.block createBlockFromEndOfData(data, READ_BLOCK_SIZE);this.size MINIMUM_SIZE;this.offset this.block.length - this.size;// 尝试找到 EOCD 的开头while (!isValid()) {this.size;if (this.size this.block.length) {if (this.size MAXIMUM_SIZE || this.size data.getSize()) {throw new IOException(Unable to find ZIP central directory records after reading this.size bytes);}// 每次多读 1 字节this.block createBlockFromEndOfData(data, this.size READ_BLOCK_SIZE);}// offset 每次向前移动 1 字节this.offset this.block.length - this.size;}}private byte[] createBlockFromEndOfData(RandomAccessData data, int size) throws IOException {int length (int) Math.min(data.getSize(), size);return data.read(data.getSize() - length, length);}// 尝试找到 EOCD 的开头private boolean isValid() {// 长度小于 EOCD 的最小长度肯定不符合if (this.block.length MINIMUM_SIZE// 读取 block 最开始的 4 个字节与 EOCD 的标记进行比较不符合则返回 false// 如果相等则找到了 EOCD 的开头|| Bytes.littleEndianValue(this.block, this.offset 0, 4) ! SIGNATURE) {return false;}// 读取注释长度 2 字节// Total size must be the structure size commentlong commentLength Bytes.littleEndianValue(this.block, this.offset COMMENT_LENGTH_OFFSET, 2);// EOCD 的字节数肯定等于 EOCD 的最小长度 注释内容的长度return this.size MINIMUM_SIZE commentLength;}/*** Return the number of ZIP entries in the file.* return the number of records in the zip*/public int getNumberOfRecords() {// 读取 block 偏移量文 10 的 2 个字节即文件数量long numberOfRecords Bytes.littleEndianValue(this.block, this.offset 10, 2);// 如果文件数量为 65535 则为 Zip64if (numberOfRecords 0xFFFF) {throw new IllegalStateException(Zip64 archives are not supported);}return (int) numberOfRecords;}}参考
java - Add more than 65535 entries jar in Spring boot - Stack Overflow压缩包Zip格式详析全网最详细_zip格式详解-CSDN博客ZIP文件格式分析 | Sp4n9x’s BlogZIP (file format) - Wikipedia