Apache Commons Compress 1.28.0 介绍与选型指南

Apache Commons Compress 1.28.0 介绍与选型指南:压缩与归档双层架构、官方示例与同类库选型对比。

Apache Commons CompressApache Commons CompressApacheJava2026/10/18

Apache Commons Compress 1.28.0 介绍与选型指南

目标:面向需要在 Java 中读写 tar/zip/7z 及 gzip/XZ/Zstd 等压缩与归档格式的开发者与架构师,梳理 Apache Commons Compress 的定位、核心架构、官方用法示例与同类选型对比。本文为认知篇(A1),仅基于官方来源联网查证,不包含本地安装与实测内容。

一、信息基准

本章说明本文所有结论的数据来源与版本依据,便于读者复核时效性。

1.1 查询日期与版本依据

项目值依据
查询日期2026-10-18本文所有联网查证均在该日完成
最新稳定版1.28.0官方站点首页标注 "Version: 1.28.0"(Last Published: 2025-07-26);Maven Central org.apache.commons:commons-compress 元数据 <release> 为 1.28.0(lastUpdated 2025-07-29)
Maven 坐标org.apache.commons:commons-compressMaven Central 元数据与官方依赖信息页
运行环境Java 8 或以上官方首页 Status 章节 "The current release requires Java 8 or above"
许可证Apache License 2.0官方站点 License 链接
源码仓库gitbox.apache.org(官方),Git 仓库可浏览官方首页 Documentation 章节

1.2 官方来源清单

二、软件概述

Apache Commons Compress 定义了一套面向归档与压缩格式的统一 Java API。官方首页表述其支持的格式:压缩器(compressor)格式包括 ar、cpio、Unix dump、tar、zip、gzip、XZ、Pack200、bzip2、7z、arj、LZMA、snappy、DEFLATE、lz4、Brotli、Zstandard、DEFLATE64 与 Z 等(来源:官方首页,查询日期 2026-10-18)。最新稳定版 1.28.0,Apache-2.0 许可,Java 8+。

2.1 项目背景

官方首页记载其代码有多个来源:bzip2、tar、zip 支持源自 Avalon 的 Excalibur(更早可追溯到 Ant),tar 包最初来自 Tim Endres 的公共领域代码,bzip2 基于 Keiron Liddle 与 Julian Seward 的 libbzip2 工作;cpio 包由 Michael Kuss 与 jRPM 项目贡献;Pack200 代码最初属于已退役的 Apache Harmony 项目(查询日期 2026-10-18)。这种"多源融合"历史也是它格式覆盖面广的原因。

2.2 版本与许可

  • 当前版本 1.28.0(官方站点 Last Published 2025-07-26;Maven Central lastUpdated 2025-07-29)。
  • 近期节奏(官方 Release Notes):1.27.0(2024-08-03)、1.27.1(2024-08-16)、1.28.0(2025-07),均为 feature/maintenance release,要求 Java 8 或以上。
  • 许可证:Apache License 2.0。

2.3 生态位

Compress 是 JVM 世界处理"非 ZIP 标准格式"(tar、7z、cpio、XZ、Zstd 等)的主要公共库:java.util.zip 只覆盖 zip/gzip 标准能力,而备份工具、大数据组件(如 Hive/Spark 的数据导出)、应用分发脚本经常需要 tar/7z/XZ 等格式。它以纯 Java + 可选原生依赖(XZ、Brotli、Zstd 经外部库桥接)的形态内嵌运行。

三、核心架构

官方用户指南(examples.html,查询日期 2026-10-18)给出了清晰的双层模型。

3.1 压缩器(Compressor)与归档器(Archiver)

官方定义:compressor 格式压缩单个数据流(通常单条目),archiver 格式把多个条目组织进单个(可能被压缩的)归档,条目以 ArchiveEntry 实例表示,通常对应单个文件或目录。当前压缩器格式为 gzip、bzip2、XZ、LZMA、Pack200、DEFLATE、Brotli、DEFLATE64、ZStandard、Z;归档器格式为 7z、ar、arj、cpio、dump、tar、zip(Pack200 只能压缩 JAR 文件)。gzip 支持大部分由 JDK 的 java.util.zip 提供。

3.2 流式抽象与缓冲约定

各类流包装调用方提供的流、直接读写而不做额外缓冲;官方强烈建议使用者先用 BufferedInputStream/BufferedOutputStream 包装底层流,再交给 Compress API(官方 General Notes "Buffering",查询日期 2026-10-18)。

3.3 工厂与格式自动探测

CompressorStreamFactory/ArchiveStreamFactory 提供按算法名创建流,以及猜测输入流格式的工厂方法(见第五章 5.2)。官方注明:LZMA 与 Brotli 格式无法被自动探测,工厂对这两类输入会直接失败。

3.4 外部依赖桥接

官方首页明确:XZ 与 LZMA 支持由公共领域的 XZ for Java 库提供;Brotli 支持由 MIT 许可的 Google Brotli 解码器提供;Zstandard 支持由 BSD 许可的 zstd-jni 提供。这三类能力需要把对应桥接库加入依赖(查询日期 2026-10-18)。

四、功能特性

4.1 格式覆盖与只读矩阵

官方说明(来源:官方首页与用户指南 General Notes,查询日期 2026-10-18):

  • 自 1.21 起,dump、arj、Brotli、DEFLATE64、Z 为只读;arj 只能读未压缩归档;
  • 7z 可读大多数压缩与加密算法,但只能写未加密归档;写侧仅支持未压缩、LZMA、LZMA2、BZIP2、Deflate(读侧额外支持 AES-256/SHA-256 与 DEFLATE64);
  • 7z 多卷(multipart)归档完全不支持写;读侧可将各分卷按序拼接(例如用 MultiReadOnlySeekableByteChannel)后读取;
  • 7z 的 solid 压缩(多文件合块压缩以提升压缩率)仅支持读取,因此写出的压缩比通常不如原生 7z 命令行工具;
  • ZIP 实现提供超出 java.util.zip 的能力(详见官方 zip 专页,如 ZipFile 随机访问与 ZipArchiveInputStream 的取舍说明)。

4.2 内存限制与 zip bomb 防护

  • 自 1.14 起,CompressorStreamFactory 构造器可设置解压/压缩的内存上限(1.14 时仅影响 Z、XZ、LZMA 解压流);
  • 自 1.19 起,SevenZFile 也支持内存上限设置;
  • 自 1.17 起,多数 CompressorInputStream、ZipArchiveInputStream 与 ZipFile.getInputStream 返回的流实现 InputStreamStatistics,可用于跟踪解压进度、在压缩比异常放大时识别潜在 zip bomb(官方 General Notes "Statistics",查询日期 2026-10-18)。

4.3 加密能力(7z 读)

Compress 支持读取但不支持写出加密 7z:读取加密归档需向 SevenZFile 构造器提供口令,未提供时抛出 PasswordRequiredException(IOException 子类)。自 1.17 起新增 char[] 口令构造器,官方推荐使用以避免 byte[] 编码错误(官方要求 UTF-16LE 编码;示例见 5.5)。

4.4 条目名安全(路径穿越)

官方用户指南 "Entry Names" 明确:读取归档时 getName 返回的是归档内原始名称,不保证是相对路径、甚至不保证在目标操作系统上是合法文件名;以条目名构造落盘文件时必须自行校验结果路径合法、或确保位于目标目录之内(查询日期 2026-10-18)。这是解压外部归档时最重要的安全约束。

五、快速上手

本章示例引自官方用户指南(https://commons.apache.org/proper/commons-compress/examples.html,查询日期 2026-10-18);官方骨架中的伪代码变量按官方文字说明补全为具体表达,未做本地运行验证。

5.1 Maven 依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.28.0</version>
</dependency>

坐标来源:Maven Central org.apache.commons:commons-compress 元数据(查询日期 2026-10-18)。

5.2 工厂创建与格式猜测

官方示例(按算法名创建压缩输出流,以及让工厂猜测压缩/归档输入流格式):

CompressorOutputStream gzippedOut = new CompressorStreamFactory()
        .createCompressorOutputStream(CompressorStreamFactory.GZIP, myOutputStream);

ArchiveInputStream input = new ArchiveStreamFactory()
        .createArchiveInputStream(originalInput);

CompressorInputStream input2 = new CompressorStreamFactory()
        .createCompressorInputStream(originalInput);

5.3 读取 tar.gz:压缩流与归档流叠加

官方示例(官方注释:把 ArchiveInputStream 包在 CompressorInputStream 之外):

try (InputStream fi = Files.newInputStream(Paths.get("my.tar.gz"));
     InputStream bi = new BufferedInputStream(fi);
     InputStream gzi = new GzipCompressorInputStream(bi);
     ArchiveInputStream o = new TarArchiveInputStream(gzi)) {
    // 逐条目读取,见 5.4 的通用提取逻辑
}

官方同样给出写出方向的最小骨架:

try (OutputStream fo = Files.newOutputStream(Paths.get("my.tar.gz"));
     OutputStream gzo = new GzipCompressorOutputStream(fo);
     ArchiveOutputStream o = new TarArchiveOutputStream(gzo)) {
    // 用 createArchiveEntry + putArchiveEntry + write + closeArchiveEntry 逐条目写入
}

5.4 通用提取逻辑(官方骨架)

官方骨架描述了所有归档格式(除 7z 走 SevenZFile)的通用提取流程,其中 targetDir 与流构造按官方文字说明补全:

File targetDir = new File("target/unpack");
try (ArchiveInputStream i = new TarArchiveInputStream(
        new BufferedInputStream(Files.newInputStream(Paths.get("my.tar.gz"))))) {
    ArchiveEntry entry = null;
    while ((entry = i.getNextEntry()) != null) {
        if (!i.canReadEntryData(entry)) {
            // 记录并跳过当前实现不支持的条目
            continue;
        }
        File f = new File(targetDir, entry.getName()); // 生产代码应校验路径,见 4.4
        if (entry.isDirectory()) {
            if (!f.isDirectory() && !f.mkdirs()) {
                throw new IOException("failed to create directory " + f);
            }
        } else {
            File parent = f.getParentFile();
            if (!parent.isDirectory() && !parent.mkdirs()) {
                throw new IOException("failed to create directory " + parent);
            }
            try (OutputStream o = Files.newOutputStream(f.toPath())) {
                IOUtils.copy(i, o);
            }
        }
    }
}

官方强调:上述骨架中的落盘文件名必须由调用方实现并校验(保证合法路径、位于目标目录内),IOUtils.copy 可复用 Commons IO 的同名工具。

5.5 7z:写入、读取与加密读取

官方示例(变量按官方文字说明补全):

// 添加条目到 7z 归档
SevenZOutputFile sevenZOutput = new SevenZOutputFile(new File("archive.7z"));
File fileToArchive = new File("data.txt");
SevenZArchiveEntry entry = sevenZOutput.createArchiveEntry(fileToArchive, "data.txt");
sevenZOutput.putArchiveEntry(entry);
sevenZOutput.write(Files.readAllBytes(fileToArchive.toPath()));
sevenZOutput.closeArchiveEntry();
sevenZOutput.close();

// 解压 7z 归档(官方注释:实际使用应补齐异常处理与资源关闭)
SevenZFile sevenZFile = new SevenZFile(new File("archive.7z"));
SevenZArchiveEntry entry2 = sevenZFile.getNextEntry();
byte[] content = new byte[entry2.getSize()];
int offset = 0;
while (offset < content.length) {
    int read = sevenZFile.read(content, offset, content.length - offset);
    offset += read;
}
sevenZFile.close();

// 读取加密 7z:推荐自 1.17 起的 char[] 口令构造器
SevenZFile encrypted = new SevenZFile(new File("archive.7z"), "secret".toCharArray());

官方另提示:SevenZFile 可配合 SeekableInMemoryByteChannel 读写内存中的 7z 归档;以 byte[] 传口令时官方要求 UTF-16LE 编码,易错,故推荐 char[] 版本。

六、适用场景与限制

6.1 适用场景

  • 备份/迁移工具:生成与还原 tar、cpio、ar 等传统 Unix 归档;
  • 应用与数据分发:跨平台读写 zip/tar.gz/7z 包,或解压 XZ/Zstd 压缩的数据分片;
  • 大数据与数据管道:处理 XZ/Zstd 压缩的文本分片(Hive/Spark 生态常见格式);
  • 需要在纯 Java 进程内完成上述能力、且接受桥接库依赖的服务端应用。

6.2 限制与注意事项

  • 写入端格式约束多:7z 只能写未加密归档、写侧算法限于未压缩/LZMA/LZMA2/BZIP2/Deflate、多卷不可写、solid 不可写(见 4.1);需要"7z 全功能写出"的场景仍需外部命令行工具或商业库;
  • 只读格式清单:arj、dump、Brotli、DEFLATE64、Z 只读;LZMA/Brotli 输入流无法自动探测格式;
  • 条目名必须校验:路径穿越风险由调用方负责(见 4.4),官方在用户指南与限制页均反复强调;
  • 桥接库依赖:XZ/LZMA、Brotli、Zstd 需分别引入 XZ for Java、Google Brotli decoder、zstd-jni,引入原生 JNI 桥接(zstd-jni)时注意目标平台的兼容性验证;
  • Pack200 特殊性:仅适用于 JAR 文件,且该格式与新版 JDK 的兼容性受 JDK 自身演进影响,使用前建议核对官方限制页。

6.3 不适合的场景

  • 只需要标准 zip 读写且无加密/分卷需求的场景,java.util.zip 已足够;
  • 需要虚拟文件系统语义(把归档当目录透明访问)的场景,TrueZIP 的 TFile 抽象更贴合(见第七章);
  • 需要高并发多线程压缩器(如 Zstd 多线程级联)的性能敏感场景,直接绑定 zstd-jni 原生 API 可获得更多控制面。

七、同类选型对比

库许可证最新稳定版最近发版(核实日 2026-10-18)社区活跃度参考兼容性
Apache Commons CompressApache-2.01.28.02025-07-26(官方站点)/ Maven lastUpdated 2025-07-29ASF 邮件列表 + JIRA;约每年 1-2 版Java 8+
TrueZIPEPL-1.0(第三方声明与项目站点)7.7.102016-08-07(Maven Central lastUpdated)项目主页为 Bitbucket(christian-schlichtherle.truezip),无官方 GitHub 计数Java 7 时代基线,维护已停滞
zip4jApache-2.0(仓库声明)2.11.62026-02-11(Maven Central lastUpdated)GitHub 2230 stars(ungh.cc)Java 8+,专注 ZIP(含 AES 加密/分卷)
XZ for Java0BSD(1.10 起;更早版本公有领域,官网声明)1.122026-03-01(官网 Releases,修复影响 1.10/1.11 的重要缺陷)官方仓库 tukaani-project/xz-java(GitHub,与 git.tukaani.org 同步);stars 渠道当日受限未采信Java 8 兼容,Java 9+ 提供 MRJ 优化

💡 技术拓展(压缩算法层与归档层的关系):gzip/bzip2/XZ/Zstd/Brotli 是"压缩算法层",处理单条字节流;tar/zip/7z 是"归档层",组织多文件结构。tar.gz = 归档层(tar)+ 压缩层(gzip)叠加,zip/7z 则在归档格式内部内置了条目级压缩。选型时先分清需要哪一层,再决定"组合两个库"还是"一个库通吃"。

选型建议:多格式、进程内、纯 Java 优先 Commons Compress;仅做 ZIP(尤其需要 AES 加密、分卷)选 zip4j 更聚焦;需要把归档当虚拟文件系统随机读写且能接受维护停滞风险的遗留系统可评估 TrueZIP;单纯追求 XZ 极致压缩比且已用 Compress 时,其默认桥接(XZ for Java 1.12)即可,无需重复引入。

八、参考链接

  1. 官方主站:https://commons.apache.org/compress/
  2. 用户指南与示例:https://commons.apache.org/proper/commons-compress/examples.html
  3. 已知限制:https://commons.apache.org/proper/commons-compress/limitations.html
  4. ZIP 专页:https://commons.apache.org/proper/commons-compress/zip.html
  5. Maven Central 元数据:https://repo1.maven.org/maven2/org/apache/commons/commons-compress/maven-metadata.xml
  6. XZ for Java 官网:https://tukaani.org/xz/java.html
  7. zip4j 仓库:https://github.com/srikanth-lingala/zip4j
  8. zstd-jni 仓库:https://github.com/luben/zstd-jni
  9. Google Brotli 仓库:https://github.com/google/brotli