Class ZipUtil
Provides static utility methods for creating, extracting, and inspecting Zip archives. Includes security protections against zip bombs and path traversal attacks.
提供创建、提取和检查Zip归档的静态工具方法。 包含针对zip炸弹和路径穿越攻击的安全保护。
Features | 主要功能:
- Zip files and directories - 压缩文件和目录
- Extract zip archives safely - 安全提取zip归档
- List and read individual entries - 列出和读取单个条目
- Fluent builder API for complex archives - 复杂归档的流式构建器API
- Path traversal protection - 路径穿越防护
- Zip bomb protection - Zip炸弹防护
Usage Examples | 使用示例:
// Zip a directory
ZipUtil.zip(sourceDir, targetZip);
// Unzip safely
ZipUtil.unzip(zipFile, outputDir);
// List entries
List<ZipEntryInfo> entries = ZipUtil.list(zipFile);
// Builder API
ZipUtil.builder()
.addFile(path1)
.addString("note.txt", "hello")
.writeTo(outputZip);
Security | 安全性:
- Thread-safe: Yes (stateless utility class) - 线程安全: 是(无状态工具类)
- Path traversal: Blocked - 路径穿越: 已阻止
- Zip bomb: Size and entry count limits - Zip炸弹: 大小和条目数限制
- Since:
- JDK 25, opencode-base-io V1.0.3
- Author:
- Leon Soo www.LeonSoo.com
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intMaximum number of entries allowed in a zip archive Zip归档中允许的最大条目数static final intMaximum entry name length allowed 允许的最大条目名长度static final longMaximum total uncompressed size allowed (4GB) 允许的最大总未压缩大小(4GB) -
Method Summary
Modifier and TypeMethodDescriptionstatic ZipBuilderbuilder()Creates a new fluent builder for assembling a zip archive 创建一个新的流式构建器用于组装zip归档static ZipResultcompress(Path zipFile, Collection<Path> sources, ZipOptions options) Compresses sources into a ZIP usingZipOptions(compression level, exclude globs, encoding, etc.) and returns aggregated statistics.static voidcompressStream(OutputStream output, List<ZipEntrySource> entries, ZipOptions options) Streams entries into the supplied output as a ZIP archive without staging to disk.static booleancontainsEntry(Path zipFile, String entryName) Checks whether a zip archive contains an entry with the given name 检查zip归档中是否包含给定名称的条目static ZipResultextract(Path zipFile, Path targetDir, ZipOptions options) Extracts a ZIP usingZipOptions(overwrite policy, anti-bomb thresholds) and returns aggregated statistics.static ZipResultextractMatching(Path zipFile, Path targetDir, List<String> patterns) Extracts entries whose names match any of the supplied glob patterns.static ZipResultextractMatching(Path zipFile, Path targetDir, List<String> patterns, ZipOptions options) Extracts entries whose names match any of the supplied glob patterns, with custom options.static List<ZipEntryInfo> Lists all entries in a zip archive 列出zip归档中的所有条目static InputStreamOpens a streamingInputStreamfor a single ZIP entry.static byte[]Reads a single entry from a zip archive 从zip归档中读取单个条目static byte[]Reads a single entry from a zip archive with a size limit 从zip归档中读取单个条目(带大小限制)static voidExtracts a zip archive to the target directory with security checks 使用安全检查将zip归档提取到目标目录static voidZips a single file or directory to the target zip file 将单个文件或目录压缩到目标zip文件static voidzip(Collection<Path> sources, Path target) Zips multiple files to the target zip file 将多个文件压缩到目标zip文件
-
Field Details
-
MAX_ENTRIES
public static final int MAX_ENTRIESMaximum number of entries allowed in a zip archive Zip归档中允许的最大条目数- See Also:
-
MAX_UNCOMPRESSED_SIZE
public static final long MAX_UNCOMPRESSED_SIZEMaximum total uncompressed size allowed (4GB) 允许的最大总未压缩大小(4GB)- See Also:
-
MAX_ENTRY_NAME_LENGTH
public static final int MAX_ENTRY_NAME_LENGTHMaximum entry name length allowed 允许的最大条目名长度- See Also:
-
-
Method Details
-
zip
Zips a single file or directory to the target zip file 将单个文件或目录压缩到目标zip文件If source is a directory, its contents are added recursively.
如果源是目录,则递归添加其内容。
- Parameters:
source- the source file or directory | 源文件或目录target- the target zip file path | 目标zip文件路径- Throws:
NullPointerException- if source or target is null | 当source或target为null时抛出OpenIOOperationException- if zipping fails | 当压缩失败时抛出
-
zip
Zips multiple files to the target zip file 将多个文件压缩到目标zip文件- Parameters:
sources- the source files | 源文件集合target- the target zip file path | 目标zip文件路径- Throws:
NullPointerException- if sources or target is null | 当sources或target为null时抛出OpenIOOperationException- if zipping fails | 当压缩失败时抛出
-
unzip
Extracts a zip archive to the target directory with security checks 使用安全检查将zip归档提取到目标目录Security protections applied:
- Path traversal detection (rejects entries containing "..")
- Resolved path must be within target directory
- Total uncompressed size limited to
MAX_UNCOMPRESSED_SIZE - Entry count limited to
MAX_ENTRIES - Entry name length limited to
MAX_ENTRY_NAME_LENGTH
- Parameters:
zipFile- the zip file to extract | 要提取的zip文件targetDir- the target directory | 目标目录- Throws:
NullPointerException- if zipFile or targetDir is null | 当zipFile或targetDir为null时抛出OpenIOOperationException- if extraction fails or security check fails | 当提取失败或安全检查失败时抛出
-
list
Lists all entries in a zip archive 列出zip归档中的所有条目- Parameters:
zipFile- the zip file path | zip文件路径- Returns:
- list of entry metadata | 条目元数据列表
- Throws:
NullPointerException- if zipFile is null | 当zipFile为null时抛出OpenIOOperationException- if reading fails | 当读取失败时抛出
-
readEntry
Reads a single entry from a zip archive 从zip归档中读取单个条目- Parameters:
zipFile- the zip file path | zip文件路径entryName- the entry name to read | 要读取的条目名- Returns:
- the entry data | 条目数据
- Throws:
NullPointerException- if zipFile or entryName is null | 当zipFile或entryName为null时抛出OpenIOOperationException- if entry not found or reading fails | 当条目未找到或读取失败时抛出
-
readEntry
Reads a single entry from a zip archive with a size limit 从zip归档中读取单个条目(带大小限制)- Parameters:
zipFile- the zip file path | zip文件路径entryName- the entry name to read | 要读取的条目名maxSize- the maximum entry size in bytes | 最大条目大小(字节)- Returns:
- the entry data | 条目数据
- Throws:
NullPointerException- if zipFile or entryName is null | 当zipFile或entryName为null时抛出IllegalArgumentException- if maxSize is not positive | 当maxSize非正数时抛出OpenIOOperationException- if entry not found, reading fails, or size limit exceeded | 当条目未找到、读取失败或超出大小限制时抛出
-
containsEntry
Checks whether a zip archive contains an entry with the given name 检查zip归档中是否包含给定名称的条目- Parameters:
zipFile- the zip file path | zip文件路径entryName- the entry name to check | 要检查的条目名- Returns:
- true if the entry exists | 如果条目存在返回true
- Throws:
NullPointerException- if zipFile or entryName is null | 当zipFile或entryName为null时抛出OpenIOOperationException- if reading the zip fails | 当读取zip失败时抛出
-
builder
Creates a new fluent builder for assembling a zip archive 创建一个新的流式构建器用于组装zip归档- Returns:
- a new ZipBuilder | 新的ZipBuilder
-
compress
Compresses sources into a ZIP usingZipOptions(compression level, exclude globs, encoding, etc.) and returns aggregated statistics. 使用ZipOptions(压缩级别、排除 glob、编码等)压缩源到 ZIP,并返回汇总统计。- Parameters:
zipFile- output ZIP path | 输出 ZIP 路径sources- files / directories to compress | 待压缩的文件 / 目录集合options- compression options | 压缩选项- Returns:
- aggregated
ZipResult| 汇总ZipResult - Throws:
NullPointerException- when any argument is null | 任一参数为 null 时OpenIOOperationException- when compression fails | 压缩失败时- Since:
- opencode-base-io V1.0.4
-
extract
Extracts a ZIP usingZipOptions(overwrite policy, anti-bomb thresholds) and returns aggregated statistics. 使用ZipOptions(覆盖策略、反炸弹阈值等)解压 ZIP,并返回汇总统计。Nested-ZIP detection note | 嵌套 ZIP 检测说明: the
maxNestingDepthcap is enforced by checking that entry names end with.zip(case-insensitive); we do NOT magic-byte sniff entry payloads. An attacker who renames a nested archive (e.g.data.bin) bypasses this filter — treat the cap as a hardening hint rather than a complete defense. Use the size / count / ratio caps for stronger guarantees.maxNestingDepth上限通过检查条目名后缀.zip(不区分大小写)来生效; 不会对条目负载做魔数嗅探。攻击者把嵌套归档改名(如data.bin)即可绕过本过滤; 把该上限视为加固提示而非完整防御,更强保证应靠大小/条目数/压缩比上限。- Parameters:
zipFile- ZIP file path | ZIP 文件路径targetDir- target directory | 目标目录options- extraction options | 解压选项- Returns:
- aggregated
ZipResult| 汇总ZipResult - Throws:
NullPointerException- when any argument is null | 任一参数为 null 时ZipBombDetectedException- when anti-bomb thresholds are breached | 触发反炸弹阈值时OpenIOOperationException- when extraction fails | 解压失败时- Since:
- opencode-base-io V1.0.4
-
extractMatching
Extracts entries whose names match any of the supplied glob patterns. 解压名称匹配任一 glob 模式的条目。Glob matching note | glob 匹配说明: each pattern is tested against BOTH the full entry path AND the file-name leaf to remain lenient with simple
"*.log"style patterns. Callers wanting strict path matching (no leaf fallback) should use"**/*.log"explicitly.每个模式同时对完整条目路径与叶子文件名匹配,兼容简单形式如
"*.log";需要严格 路径匹配(不走叶子兜底)时请显式使用"**/*.log"。 -
extractMatching
-
openEntry
Opens a streamingInputStreamfor a single ZIP entry. The caller MUST close the returned stream; closing it also releases the underlyingZipFile. 打开单个 ZIP 条目的流式InputStream。调用方必须关闭返回的流,关闭时同时释放底层ZipFile。- Parameters:
zipFile- ZIP file path | ZIP 文件路径entryName- entry name to open | 要打开的条目名- Returns:
- streaming entry content | 条目流式内容
- Throws:
NullPointerException- when any argument is null | 任一参数为 null 时OpenIOOperationException- when the entry is missing or read fails | 条目缺失或读取失败时- Since:
- opencode-base-io V1.0.4
-
compressStream
public static void compressStream(OutputStream output, List<ZipEntrySource> entries, ZipOptions options) Streams entries into the supplied output as a ZIP archive without staging to disk. 直接把流式条目写入给定输出,构建 ZIP 而无需先落盘。- Parameters:
output- output stream to write the ZIP to | 接收 ZIP 数据的输出流entries- entry sources | 流式条目options- compression options | 压缩选项- Throws:
NullPointerException- when any argument is null | 任一参数为 null 时OpenIOOperationException- when writing fails | 写入失败时- Since:
- opencode-base-io V1.0.4
-