java解压zip核心是zipinputstream配合文件输出流,需校验路径防穿越、规范编码处理、用缓冲区读写避免内存溢出,并每次调用closeentry()。

Java 中解压 ZIP 压缩包,本质是用 ZipInputStream 读取压缩流,再用普通文件输出流(如 FileOutputStream 或 Files.write())写入磁盘。这不是“文件读写”本身的功能,而是通过标准 IO 流协作完成的解压操作。
关键不在“读写”,而在如何安全、正确地把 ZIP 条目内容提取到目标路径。
解压 ZIP 的核心流程
- 用
FileInputStream打开 ZIP 文件 - 包装成
ZipInputStream - 循环调用
getNextEntry()获取每个ZipEntry - 对每个非目录条目,创建对应目标文件并写入内容
-
每处理完一个条目,必须调用
closeEntry()
示例骨架:
try (ZipInputStream zis = new ZipInputStream(new FileInputStream("a.zip"))) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (entry.isDirectory()) {
new File("out/" + entry.getName()).mkdirs();
} else {
Files.createDirectories(Paths.get("out/" + entry.getName()).getParent());
Files.write(Paths.get("out/", entry.getName()), zis.readAllBytes());
}
zis.closeEntry(); // 必须!否则后续条目可能读错
}
}
路径安全:防 ../ 路径穿越
ZIP 文件中条目名可能含 ../../etc/passwd,直接拼接会写到任意目录。
必须校验并规范化:
- 用
Paths.get(entry.getName()).normalize()得到规范路径 - 检查是否以目标根目录为前缀,例如:
Path target = destDir.toPath().resolve(entry.getName()).normalize(); if (!target.startsWith(destDir.toPath().toAbsolutePath().normalize())) { throw new IOException("Suspicious path: " + entry.getName()); }
跳过非法路径,不写入、不创建。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
中文文件名支持
- JDK 7+ 起,
ZipOutputStream构造时可传Charset(如StandardCharsets.UTF_8),确保压缩端写入 UTF-8 编码的条目名 -
ZipInputStream本身无 Charset 参数,但现代 JDK(9+)默认能识别 UTF-8 编码的条目名 - 若遇到旧 ZIP(如 Windows 自带压缩工具生成的 GBK 编码),建议改用 Apache Commons Compress 库,它支持显式指定解压编码
缓冲读写更高效(推荐)
避免 readAllBytes() 加载大文件进内存,用固定缓冲区边读边写:
byte[] buf = new byte[8192];
while (true) {
int len = zis.read(buf);
if (len == -1) break;
out.write(buf, 0, len);
}
配合 try-with-resources 管理 FileOutputStream,确保资源释放。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










