zipinputstream 是 java 中用于流式解压 zip 文件的工具,需顺序读取条目、校验路径防遍历、手动写入文件并调用 closeentry()。

ZipInputStream 是 Java 标准库中用于逐个读取 ZIP 文件条目(entry)的流式解压工具,适合处理大文件或内存受限场景。它不支持随机访问,必须按顺序读取每个 ZipEntry,也不能直接解压整个 ZIP 到磁盘——需要你手动创建文件、写入数据。
核心步骤:打开流 → 遍历条目 → 提取内容
使用 ZipInputStream 解压,关键在于三步循环:
- 用
FileInputStream包装 ZIP 文件,再套上ZipInputStream - 反复调用
getNextEntry()获取下一个条目,返回null表示结束 - 对每个非目录条目(
isDirectory() == false),用普通字节流读取其内容并保存
安全提取:避免路径遍历攻击
ZIP 文件中的条目路径可能含 ../,直接拼接会写到任意目录(如系统根目录)。必须校验路径:
- 用
ZipEntry.getName()获取原始路径 - 规范化路径(如
Paths.get(entryName).normalize()) - 检查是否以目标解压目录为前缀(如
targetDir.toPath().resolve(normalizedPath).startsWith(targetDir.toPath())) - 跳过非法路径条目,或抛出异常
提取文件数据:字节数组 or 输出流?
根据用途选择读取方式:
- 想获取某文件的完整内容(比如解析 JSON):用
ByteArrayOutputStream缓存,再转成byte[]或String - 想保存到磁盘:创建对应
FileOutputStream,边读ZipInputStream边写,每次read(buf)处理一块(推荐 8192 字节缓冲区) - 注意:每个条目读完后,**必须调用
closeEntry()**,否则下一个getNextEntry()可能失败或跳过数据
完整示例:解压到指定目录并返回文件列表
以下代码安全解压 ZIP 并跳过目录和非法路径:
public static List<file> unzip(File zipFile, File destDir) throws IOException {
List<file> extracted = new ArrayList();
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String name = entry.getName();
Path targetPath = destDir.toPath().resolve(name).normalize();
// 检查是否逃逸出目标目录
if (!targetPath.startsWith(destDir.toPath().normalize())) {
continue; // 或 throw new IOException("Invalid path: " + name);
}
File targetFile = targetPath.toFile();
if (entry.isDirectory()) {
targetFile.mkdirs();
} else {
targetFile.getParentFile().mkdirs();
try (FileOutputStream fos = new FileOutputStream(targetFile)) {
byte[] buf = new byte[8192];
int len;
while ((len = zis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
}
extracted.add(targetFile);
}
zis.closeEntry(); // 关键!
}
}
return extracted;
}</file></file>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











