Arcana:一个支持几乎所有归档格式的纯Java库
Arcana 是一个开源 Java 库兼命令行工具,可列出、提取并识别 40 多种归档、压缩和磁盘映像格式,不含任何原生代码,也不依赖任何第三方库。它运行于 Java 8 及以上版本,打包后仅 1.2 MB,以 Apache 2.0 许可发布在 Maven Central 上,坐标为 io.github.realburst:arcana。
为什么还要再写一个归档库?
如果你曾经在 Java 应用里打开“用户上传的随便什么文件”,那你一定熟悉这套流程。ZIP 在 JDK 里就有。Apache Commons Compress 覆盖了 TAR、7z、CPIO、AR 以及常见压缩器,但某些编解码器需要额外的库,Zstandard 还要走 JNI 绑定。RAR 需要另一个库,而纯 Java 的 RAR 5 支持很难找到。至于 CAB、MSI、ISO、WIM 或安装程序 .exe,通常的答案是借助原生绑定打包 7-Zip,并且每个操作系统和 CPU 各配一个二进制。
我想要的是一个 JAR,能在任何 JVM 上完成上述所有事情,无需安装任何东西,也无需加载任何原生库。这就是 Arcana:单一入口,按内容而非文件扩展名检测格式,并且无论文件是 .tar.zst、RAR 5 分卷集合、MSI 包还是 macOS .dmg,用的都是同一套 API。
Arcana 能做什么
Arcana 可以提取它支持的每一种格式,并能创建最常见的那些格式。
加密归档同样受支持:ZIP 和 7z 支持 AES-256(读写皆可),RAR 4 和 RAR 5 支持 AES-128 与 AES-256。任何压缩器内部的 TAR 或 CPIO 都能一步解开,而那些“伪装成普通文件”的归档(.docx、.odt、.epub、.apk、.jar)也能像普通归档一样打开。
除了解压,Arcana 还可以:
- 识别任意文件:归档类型与版本、可执行文件(PE、ELF、Mach-O)、安装程序、带尺寸的图片、PDF、SQLite、字体;
- 恢复损坏的归档:强制提取会保留所有可读内容,并输出一份关于每个文件状态的报告;
- 拆分黏连在一起的文件,例如安装程序或固件镜像;
- 加载插件以支持更多格式。官方插件可处理 Inno Setup、NSIS、InstallShield 和 WiX Burn 安装程序,以及 UPX 加壳的可执行文件。
快速上手
添加依赖:
提取和列出永远不需要你说明文件是什么:格式是按其内容检测的。
创建归档同样简短:
同一个 JAR 也是一个命令行工具:
在 Windows 上,还有一个可选脚本会向资源管理器右键菜单添加“Arcana Unpack / List / Info”三项。
默认安全
归档提取器按定义就要读取不可信输入,因此 Arcana 把每个文件都当作敌意对象来处理。
- 没有路径穿越。 在写入任何内容之前,条目名称都会先被清洗:不允许绝对路径,不允许
..,也不允许 Windows 禁止的字符。一个“zip slip”条目无法逃出目标文件夹。 - 没有解压炸弹。 每次提取都在可于运行时修改的限制下进行(
ExtractionLimits):写入 1 GiB 后输出/输入比上限为 1000,可选的总体积上限,以及至少 256 MiB 的可用磁盘空间。 - 内存有界。 解码器会限制头部所能索取的上限:Zstandard 窗口被限制在 128 MiB,与
zstd工具一致;7z 密钥派生被限制在2^24轮。精心构造的头部只会得到错误,而不是OutOfMemoryError。 - 校验和会被验证。 CRC32、Adler-32、BLAKE2sp、XXH64、WinZip AES 的 HMAC:只要格式中存有校验和,Arcana 就会校验并报告不匹配。
- 插件必须公开其代码。 除非插件 JAR 包含其源代码、声明其许可证与源码 URL,并使用自己的包名,否则会被拒绝。这并不能让插件变安全,但能让它可被审查。
内部实现
每个解码器都用 Java 编写:Deflate64、LZMA 与 LZMA2、PPMd、Zstandard、Brotli、LZ4、LZX、LZMS、XPRESS、LZFSE 与 LZVN、ADC、LZO1X、RAR 4 与 RAR 5 算法、AES 以及密钥派生。核心部分约 80,000 行 Java 8 代码,除 JDK 外没有任何依赖。它是依据公开规范编写的:PKWARE APPNOTE、7-Zip 格式说明、微软公开规范(MS-CAB、LZX、MS-XCA)、Zstandard 的 RFC 8878、Brotli 的 RFC 7932、HFS+ 的 Apple TN1150。
有几项设计选择塑造了这个库:
- 按内容检测。 先看魔数,再看尾部特征(DMG 通过其最后 512 字节中的“koly”块识别),最后才看文件扩展名。被改过名的文件照样能打开。
- 格式允许时采用流式处理。 单流格式从
InputStream解码,并使用有界缓冲。Zstandard 解码器只保留当前帧的窗口,因此一个数 GB 的.tar.zst只需几十 MB 堆内存即可解码。 - 格式需要时采用随机访问。 磁盘映像是惰性读取的:DMG 分区借助小型缓存逐块解码,绝不会整个载入内存。
- 用真实名称,而非内部键。 MSI 会按其安装的文件树提取,使用其
File和Directory表中的名称,而不是一个充满晦涩键名的 cab 包。
每个版本都会经过回归测试套件。约 180 个小型样本随代码一同提交:每种格式和方法各一个,外加必须干净失败、绝不挂起的损坏文件。另有一个真实文件语料库(安装程序、来自 GitHub Releases 的 DMG 镜像、MSI 包)会对照提交的 SHA-256 参考值进行检查。仓库中每种格式还有一页技术文档,涵盖检测、布局、支持的方法、限制以及所用来源。
当前局限
Arcana 是一个年轻的项目,仓库为每种格式维护着一份公开的已知问题清单。在你依赖它之前,主要的局限有:
- 提取优先。 写入仅限 ZIP、7z、TAR(+ gz、bz2、xz、lz4)、GZIP、BZIP2、XZ、LHA 和 CAB。Arcana 无法创建 RAR、Zstandard 或 Brotli 文件,也无法就地更新已有归档。
- 某些文件系统只能原样复制。 DMG 内的 APFS 卷会被作为原始映像提取,而不会展开为文件。加密和稀疏 DMG 映像、拆分 WIM 文件(
.swm)以及某些少见的压缩方法(旧的 LHA 方法、CAB 中的 Quantum)不受支持。 - 纯 Java 是有代价的。 解码器对大多数用途来说足够快,但比不上原生代码。在为该项目所做的基准测试中,Zstandard 解码器达到原生
zstd库约 60% 的速度。 - 边界情况仍然存在。 少数损坏或不寻常的文件仍会抛出原始的 Java 异常而不是清晰的消息,或比参考工具更缺乏容忍度。这些情况都会记录相关文件与代码行,让你在使用某种格式于生产环境前先行判断。
如果某个文件失败,提交一个包含命令行、并在可能时附带该文件或重建方法的 issue,是最快的修复途径。## 试一试
最快的测试方法,是把 Arcana 指向你“下载”文件夹里最奇怪的文件,对它运行 arcana i,然后运行 arcana x。如果你维护的 Java 应用会接收用户上传的归档文件,试着用一个依赖替换原生绑定或一连串库,然后告诉我哪里会出问题。
- 源码、发布版本和文档:GitHub 上的 Arcana
- Maven Central:
io.github.realburst:arcana - 格式页面和已知问题
- 为自己的格式编写插件
欢迎提交 issue、失败的样本文件和插件。如果 Arcana 帮你省掉了一个依赖或一个原生二进制文件,在 GitHub 上加星标能帮助其他 Java 开发者找到它。
发现错误或有补充?在 GitHub 上编辑此页面
作者
Stéphane Bury
Stéphane Bury 是常驻比利时的 Java 开发者和 IT 顾问。他维护纯 Java 归档库 Arcana,以及纯 Java RAR 解压器 unrar5j。
相关文章
-
Foojay 播客 #98:JNI 之痛的终结:WebAssembly 如何悄然取代 Java 中的原生库
播客 · Andrea Peruffo、Frank Delporte · 2026 年 6 月 15 日 · 606 次浏览 -
引导 Java 文件系统
教程 · 用例 · Scott Sosna · 2026 年 1 月 29 日 · 3,923 次浏览 -
使用 Java 和 io_uring 进行异步文件 IO
Java · Java Core · Project Panama · David Vlijmincx · 2025 年 4 月 18 日 · 5,548 次浏览 -
一天内 7 个 Jackson CVE:AI 辅助安全研究
Java · 安全 · Steve Poole · 2026 年 6 月 29 日 · 2,487 次浏览