当前位置: 首页 > news >正文

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 确实解决了问题。

image-20240625151243205

问题

回答一中的代码来自 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 的相关代码。

image-20240625173000853

zip、zip64 功能上的区别

zip64 格式是标准 zip 格式的扩展,实际上消除了 zip 存档中文件大小和数量的限制。

每种格式允许的最大值总结如下:

Standard FormatZip64 Format
Number of Files Inside an Archive65,5352^64 - 1
Size of a File Inside an Archive [bytes]4,294,967,2952^64 - 1
Size of an Archive [bytes]4,294,967,2952^64 - 1
Number of Segments in a Segmented Archive999 (spanning) 65,535 (splitting)4,294,967,295 - 1
Central 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 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 的&#xff1f; 参考 spring boot 版本是 2.1.8.RELEASE&#xff0c;引入以…...

BASH and SH in SHELL scripts

一、执行脚本的现象 为了测试一个小的功能&#xff0c;写了一个小脚本&#xff0c;类似的内容如下&#xff1a; #!/bin/shecho "start api test ......"for((i1;i<10;i)); do echo "cur id :" $i; done echo "end."执行一下&#xff0c;“…...

Qt Creator创建一个用户登录界面

目录 1 界面设计 2 代码 2.1 登录界面 2.2 注册界面 2.3 登陆后的界面 3 完整资源 这里主要记录了如何使用Qt Creator创建一个用户登录界面&#xff0c;能够实现用户的注册和登录功能&#xff0c;注册的用户信息存储在了一个文件之中&#xff0c;在登录时可以比对登录信息…...

等保测评练习卷14

等级保护初级测评师试题14 姓名&#xff1a; 成绩&#xff1a; 判断题&#xff08;10110分&#xff09; 1. 方案编制活动中测评对象确定、测评指…...

学懂C#编程:常用高级技术——学会C#多线程开发(三):学会线程池的使用

在C#中&#xff0c;线程池&#xff08;ThreadPool&#xff09;是一种用于管理线程的机制&#xff0c;它可以有效地重用线程&#xff0c;减少线程创建和销毁的开销&#xff0c;从而提高程序的性能。线程池通常用于执行不需要立即完成的任务&#xff0c;如后台任务、异步操作等。…...

maven-gpg-plugin插件

开源项目SDK&#xff1a;https://github.com/mingyang66/spring-parent 个人文档&#xff1a;https://mingyang66.github.io/raccoon-docs/#/ 一、敏感信息泄漏警告 执行mvn install或mvn deploy时控制台会报如下告警&#xff1a; [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 这是主函数&#xff0c;数一下就发现可以溢出最后的0x4008d0 然后会执行到这里&#xff0c;逻辑就是在v0上写shellcode&#xff0c;不过执行写0x10&#xff0c;不够sh&#xff0c;很明显要先read。 以下是exp: from pwn import * context.archamd64 ioprocess(./vuln)…...

DIYGW UniApp低代码可视化平台:高效、灵活、安全的应用开发新途径

一、引言 在数字化快速发展的今天&#xff0c;企业对于快速构建多端应用的需求日益增长。然而&#xff0c;传统的应用开发方式往往面临周期长、成本高、技术门槛高等问题。为了解决这些问题&#xff0c;DIYGW UniApp低代码可视化平台应运而生&#xff0c;它以高效率、多端使用…...

Python爬虫技术及其原理探秘

导言 随着互联网的发展&#xff0c;大量的数据被存储在网络上&#xff0c;而我们需要从中获取有用的信息。Python作为一种功能强大且易于学习的编程语言&#xff0c;被广泛用于网络爬虫的开发。本文将详细介绍Python爬虫所需的技术及其原理&#xff0c;并提供相关的代码案例。…...

堆和栈的区别及应用场景

堆和栈的区别及应用场景 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在计算机科学和编程领域&#xff0c;堆&#xff08;Heap&#xff09;和栈&#xff08…...

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的子系统我们已经大致学习完了&#xff0c;笔者…...

【Mac】Listen 1 for Mac(最强的音乐搜索工具)软件介绍

软件介绍 Listen 1 for Mac 是一款非常方便的音乐播放软件&#xff0c;主要功能是集成多个音乐平台&#xff0c;让用户可以方便地搜索、播放和管理音乐。它是一个用 Python 语言开发的免费开源综合音乐搜索工具项目&#xff0c;最大的亮点在于可以搜索和播放来自网易云音乐&am…...

nginx 1024 worker_connections are not enough while connecting to upstream

现象 请求api响应慢&#xff0c;甚至出现504 gateway timeout&#xff0c;重启后端服务不能恢复&#xff0c;但重启nginx可以恢复。 解决方案 worker_connections使用了默认值 1024&#xff0c;当流量增长时&#xff0c;导致连接不够 在nginx.conf中修改连接数就可以了&…...

在Ubuntu 16.04上安装和配置Elasticsearch的方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 Elasticsearch 是一个用于实时分布式搜索和数据分析的平台。它因易用性、强大功能和可扩展性而备受欢迎。 Elasticsearch 支持 R…...

C#给SqlSugar封装一个单例类

.NET兼职社区 可以直接用&#xff0c;轻量方便&#xff0c;无需重复造轮子。 这里只对CRUD进行封装&#xff0c;我的应用比较简单。 using SqlSugar; using System.Collections.Generic;namespace MusicApp.Assist {internal class SqlSugarAssist{private static readonly ob…...

Postman接口测试工具的原理及应用详解(六)

本系列文章简介&#xff1a; 在当今软件开发的世界中&#xff0c;接口测试作为保证软件质量的重要一环&#xff0c;其重要性不言而喻。随着前后端分离开发模式的普及&#xff0c;接口测试已成为连接前后端开发的桥梁&#xff0c;确保前后端之间的数据交互准确无误。在这样的背景…...

【算法 之插入排序 原理及案例】

插入排序原理&#xff1a; 插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常…...

第一节:如何开发第一个spring boot3.x项目(自学Spring boot 3.x的第一天)

大家好&#xff0c;我是网创有方&#xff0c;从今天开始&#xff0c;我会记录每篇我自学spring boot3.x的经验。只要我不偷懒&#xff0c;学完应该很快&#xff0c;哈哈&#xff0c;更新速度尽可能快&#xff0c;想和大佬们一块讨论&#xff0c;如果需要讨论的欢迎一起评论区留…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

go 里面的指针

指针 在 Go 中&#xff0c;指针&#xff08;pointer&#xff09;是一个变量的内存地址&#xff0c;就像 C 语言那样&#xff1a; a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10&#xff0c;通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...