spring boot jar 启动报错 Zip64 archives are not supported
spring boot jar 启动报错 Zip64 archives are not supported
- 原因、解决方案
- 问题
- 为什么 spring boot 不支持 zip64
- zip、zip64 功能上的区别
- zip 的文件格式
- spring-boot-loader 是如何判断是否是 zip64 的?
- 参考
spring boot 版本是 2.1.8.RELEASE,引入以下 phoenix 依赖之后启动报错。
<dependency><groupId>org.apache.phoenix</groupId><artifactId>phoenix-client-hbase-2.4</artifactId><version>5.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.jar'at 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 方法,依赖如下:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-loader</artifactId><version>2.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 Format Zip64 Format Number of Files Inside an Archive 65,535 2^64 - 1 Size of a File Inside an Archive [bytes] 4,294,967,295 2^64 - 1 Size of an Archive [bytes] 4,294,967,295 2^64 - 1 Number of Segments in a Segmented Archive 999 (spanning) 65,535 (splitting) 4,294,967,295 - 1 Central Directory Size [bytes] 4,294,967,295 2^64 - 1
zip 的文件格式
zip格式压缩包主要由三大部分组成:
数据区、中央目录记录区(也有叫核心目录记录)、中央目录记录尾部区。数据区是由一系列
本地文件记录组成,本地文件记录主要是记录了压缩前后文件的元数据以及存放压缩后的文件。中央目录记录区是有一系列
中央目录记录所组成,一条中央目录记录对应数据区中的一个压缩文件记录。中央目录记录尾部(End of central directory record)主要作用是用来定位
中央目录记录区的开始位置,同时记录压缩包的注释内容。
End of central directory record (EOCD)
| Offset | Bytes | Description[33] | 中文 |
|---|---|---|---|
| 0 | 4 | End of central directory signature = 0x06054b50 | 签名 |
| 4 | 2 | Number of this disk (or 0xffff for ZIP64) | |
| 6 | 2 | Disk where central directory starts (or 0xffff for ZIP64) | |
| 8 | 2 | Number of central directory records on this disk (or 0xffff for ZIP64) | |
| 10 | 2 | Total number of central directory records (or 0xffff for ZIP64) | 文件数量(ZIP64 为 0xffff ) |
| 12 | 4 | Size of central directory (bytes) (or 0xffffffff for ZIP64) | |
| 16 | 4 | Offset of start of central directory, relative to start of archive (or 0xffffffff for ZIP64) | |
| 20 | 2 | Comment length (n) | 注释长度 |
| 22 | n | Comment |
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 href="https://en.wikipedia.org/wiki/Zip_%28file_format%29">Zip 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 Blog
- ZIP (file format) - Wikipedia
相关文章:
spring boot jar 启动报错 Zip64 archives are not supported
spring boot jar 启动报错 Zip64 archives are not supported 原因、解决方案问题为什么 spring boot 不支持 zip64zip、zip64 功能上的区别zip 的文件格式spring-boot-loader 是如何判断是否是 zip64 的? 参考 spring boot 版本是 2.1.8.RELEASE,引入以…...
BASH and SH in SHELL scripts
一、执行脚本的现象 为了测试一个小的功能,写了一个小脚本,类似的内容如下: #!/bin/shecho "start api test ......"for((i1;i<10;i)); do echo "cur id :" $i; done echo "end."执行一下,“…...
Qt Creator创建一个用户登录界面
目录 1 界面设计 2 代码 2.1 登录界面 2.2 注册界面 2.3 登陆后的界面 3 完整资源 这里主要记录了如何使用Qt Creator创建一个用户登录界面,能够实现用户的注册和登录功能,注册的用户信息存储在了一个文件之中,在登录时可以比对登录信息…...
等保测评练习卷14
等级保护初级测评师试题14 姓名: 成绩: 判断题(10110分) 1. 方案编制活动中测评对象确定、测评指…...
学懂C#编程:常用高级技术——学会C#多线程开发(三):学会线程池的使用
在C#中,线程池(ThreadPool)是一种用于管理线程的机制,它可以有效地重用线程,减少线程创建和销毁的开销,从而提高程序的性能。线程池通常用于执行不需要立即完成的任务,如后台任务、异步操作等。…...
maven-gpg-plugin插件
开源项目SDK:https://github.com/mingyang66/spring-parent 个人文档:https://mingyang66.github.io/raccoon-docs/#/ 一、敏感信息泄漏警告 执行mvn install或mvn deploy时控制台会报如下告警: [WARNING] Parameter passphrase (user pr…...
Linux——echo命令,管道符,vi/vim 文本编辑器
1.echo 命令 作用 向终端设备上输出字符串或变量的存储数据 格式 echo " 字符串 " echo $ 变 量名 [rootserver ~] # echo $SHELL # 输出变量的值必须加 $ /bin/bash [rootserver ~] # str1" 我爱中国 " # 自定义变量 echo 重定向输出到文件 ec…...
CISCN--西南半决赛--pwn
1.vuln 这是主函数,数一下就发现可以溢出最后的0x4008d0 然后会执行到这里,逻辑就是在v0上写shellcode,不过执行写0x10,不够sh,很明显要先read。 以下是exp: from pwn import * context.archamd64 ioprocess(./vuln)…...
DIYGW UniApp低代码可视化平台:高效、灵活、安全的应用开发新途径
一、引言 在数字化快速发展的今天,企业对于快速构建多端应用的需求日益增长。然而,传统的应用开发方式往往面临周期长、成本高、技术门槛高等问题。为了解决这些问题,DIYGW UniApp低代码可视化平台应运而生,它以高效率、多端使用…...
Python爬虫技术及其原理探秘
导言 随着互联网的发展,大量的数据被存储在网络上,而我们需要从中获取有用的信息。Python作为一种功能强大且易于学习的编程语言,被广泛用于网络爬虫的开发。本文将详细介绍Python爬虫所需的技术及其原理,并提供相关的代码案例。…...
堆和栈的区别及应用场景
堆和栈的区别及应用场景 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在计算机科学和编程领域,堆(Heap)和栈(…...
vant的dialog触发了其他overlay
原代码: <!-- dialog --><van-dialog v-model"showTipsDialog" title"温馨提示"><p>dialog内容</p></van-dialog><!-- overlay --><van-overlay style"display: flex" :show"showLoadingOverlay&q…...
Linux驱动开发笔记(十二)并发与竞争
文章目录 前言一、并发与竞争的引入1.1 并发1.2 竞争1.3 解决方法 二、原子操作2.1 概念2.2 使用方法 三、自旋锁3.1 概念3.2 使用方法3.3 自旋锁死锁 四、信号量4.1 概念4.2 使用方法 五、互斥锁5.1 概念5.2 使用方法 前言 Linux的子系统我们已经大致学习完了,笔者…...
【Mac】Listen 1 for Mac(最强的音乐搜索工具)软件介绍
软件介绍 Listen 1 for Mac 是一款非常方便的音乐播放软件,主要功能是集成多个音乐平台,让用户可以方便地搜索、播放和管理音乐。它是一个用 Python 语言开发的免费开源综合音乐搜索工具项目,最大的亮点在于可以搜索和播放来自网易云音乐&am…...
nginx 1024 worker_connections are not enough while connecting to upstream
现象 请求api响应慢,甚至出现504 gateway timeout,重启后端服务不能恢复,但重启nginx可以恢复。 解决方案 worker_connections使用了默认值 1024,当流量增长时,导致连接不够 在nginx.conf中修改连接数就可以了&…...
在Ubuntu 16.04上安装和配置Elasticsearch的方法
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 简介 Elasticsearch 是一个用于实时分布式搜索和数据分析的平台。它因易用性、强大功能和可扩展性而备受欢迎。 Elasticsearch 支持 R…...
C#给SqlSugar封装一个单例类
.NET兼职社区 可以直接用,轻量方便,无需重复造轮子。 这里只对CRUD进行封装,我的应用比较简单。 using SqlSugar; using System.Collections.Generic;namespace MusicApp.Assist {internal class SqlSugarAssist{private static readonly ob…...
Postman接口测试工具的原理及应用详解(六)
本系列文章简介: 在当今软件开发的世界中,接口测试作为保证软件质量的重要一环,其重要性不言而喻。随着前后端分离开发模式的普及,接口测试已成为连接前后端开发的桥梁,确保前后端之间的数据交互准确无误。在这样的背景…...
【算法 之插入排序 原理及案例】
插入排序原理: 插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常…...
第一节:如何开发第一个spring boot3.x项目(自学Spring boot 3.x的第一天)
大家好,我是网创有方,从今天开始,我会记录每篇我自学spring boot3.x的经验。只要我不偷懒,学完应该很快,哈哈,更新速度尽可能快,想和大佬们一块讨论,如果需要讨论的欢迎一起评论区留…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
