Java中用ZipInputStream解压ZIP文件的核心流程是逐条读取ZipEntry→安全校验路径→区分创建目录或文件→缓冲写入内容;关键须防范zip slip攻击、正确管理流生命周期,并严格区分ZIP与GZIP格式。

Java 中用 ZipInputStream 解压 ZIP 文件,核心是按“逐条读取条目 → 创建对应文件/目录 → 写入内容”的流程操作,关键在于正确处理条目类型(文件 or 目录)、路径安全校验、流的嵌套关闭。
1. 用 ZipInputStream 逐个读取 ZIP 条目
ZipInputStream 是装饰器流,包装一个底层输入流(如 FileInputStream),通过 getNextEntry() 按顺序获取每个 ZipEntry。每次调用后,流位置自动跳转到该条目数据起始处,可直接读取内容。
- 必须循环调用
getNextEntry(),直到返回null - 每个
ZipEntry包含名称、是否为目录、压缩大小、原始大小等信息 - 不能跳过条目或随机访问 —— 它只支持顺序读取
2. 安全创建目标路径并区分文件与目录
解压前需将 ZipEntry.getName() 转为本地文件系统路径,并做路径校验(防 zip slip 攻击),再根据 isDirectory() 判断创建目录或文件。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
Paths.get(outputDir, entryName)构建目标路径,避免字符串拼接 - 检查路径是否超出
outputDir范围:用toRealPath()或startsWith(outputDir.toRealPath()) - 若
entry.isDirectory()为 true,用Files.createDirectories()创建目录 - 否则先创建父目录(
Files.createDirectories(path.getParent())),再用Files.newOutputStream(path)写入
3. 正确读写条目数据并管理资源
每个条目数据需从 ZipInputStream 读取,写入对应文件输出流。注意:不要在循环中提前关闭 ZipInputStream,否则后续条目无法读取。
立即学习“Java免费学习笔记(深入)”;
- 使用 try-with-resources 管理每个条目的
OutputStream,但ZipInputStream应在外层 try 中声明 - 推荐缓冲读写(如 8KB 字节数组),避免单字节拷贝
- 调用
zipIn.closeEntry()并非必须,但显式调用有助于明确边界(尤其涉及 CRC 校验时)
4. 注意 GZIP 和 ZIP 的区别
ZipInputStream 只用于 ZIP 格式(含多个文件/目录结构)。GZIP 是单文件压缩格式,对应的是 GZIPInputStream,它不解析条目,仅解压一个流 —— 不能用它解压 .zip 文件,也不能用 ZipInputStream 解压 .gz 文件。
- 扩展名不是判断依据:.zip 一定是 ZIP 格式;.gz 一定是 GZIP;.tar.gz 需先用
GZIPInputStream解包,再用TarArchiveInputStream(需 Apache Commons Compress)解析 - 如果误用
ZipInputStream读 .gz 文件,会抛ZipException: error in opening zip file

















