java原生java.util.zip可完成zip压缩解压,关键需正确使用zipoutputstream和zipinputstream:压缩时路径标准化为正斜杠、递归处理目录、每个条目后调用closeentry();解压时须防路径穿越、校验合法性;中文名需显式指定utf-8编码。

Java原生压缩流(java.util.zip)可以不依赖第三方库完成ZIP打包与解压,核心是正确使用 ZipOutputStream 和 ZipInputStream,并注意文件路径处理、编码兼容性与资源释放。
打包多个文件为ZIP(含目录结构)
关键点在于:遍历文件/目录时递归构建相对路径,写入 ZIP 条目时用 ZipEntry 表示每个文件,并确保路径分隔符统一为正斜杠(/),避免 Windows 下反斜杠导致解压异常。
- 创建
FileOutputStream→ 包装为ZipOutputStream - 对每个待压缩文件调用
zipOut.putNextEntry(new ZipEntry(相对路径)) - 用普通字节流(如
Files.newInputStream())读取源文件,写入zipOut - 每个条目写完后必须调用
zipOut.closeEntry() - 最后关闭
zipOut(自动触发finish())
示例片段(简化):
try (ZipOutputStream zipOut = new ZipOutputStream(
new FileOutputStream("output.zip"))) {
for (Path file : filesToZip) {
String entryName = root.relativize(file).toString().replace("\", "/");
if (Files.isRegularFile(file)) {
zipOut.putNextEntry(new ZipEntry(entryName));
Files.copy(file, zipOut);
zipOut.closeEntry();
}
}
}
解压ZIP到指定目录(安全处理路径)
重点防范路径穿越攻击(如 ../etc/passwd)。不能直接用 ZipEntry.getName() 构造目标路径,需规范化并校验是否在目标目录内。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 用
ZipInputStream逐个读取ZipEntry - 对每个条目名做
Paths.get(entryName).normalize(),再检查是否以目标根目录为前缀 - 若为目录(名字以
/结尾),创建对应File并mkdirs() - 若为文件,创建父目录,再用
Files.write()写入内容 - 务必跳过非法路径(如含
..且超出根目录)
中文文件名支持(UTF-8 编码)
标准 java.util.zip 默认使用 IBM437 编码,中文会乱码。Java 7+ 提供 ZipOutputStream(OutputStream, Charset) 构造方法,显式传入 StandardCharsets.UTF_8 即可;解压时 ZipInputStream 无 Charset 参数,但多数现代 ZIP 工具(包括 Java 自己生成的 UTF-8 ZIP)能自动识别,无需额外处理。
- 打包时:用
new ZipOutputStream(out, StandardCharsets.UTF_8) - 解压时:通常无需干预,但若遇到乱码,可尝试用
ZipFile+getInputStream(ZipEntry)替代ZipInputStream(ZipFile更可靠解析 UTF-8 条目名)
常见坑与注意事项
容易忽略但影响稳定性的问题:
-
未关闭 ZipEntry 流:写入文件后必须
closeEntry(),否则 ZIP 结构损坏 -
未处理空目录:ZIP 中目录以
/结尾的条目存在,需手动创建对应目录 -
未设置压缩级别:默认
Deflater.DEFAULT_COMPRESSION,可调用setLevel(Deflater.BEST_COMPRESSION)或NO_COMPRESSION - 大文件内存风险:避免一次性读入整个文件,用固定缓冲区(如 8KB)循环复制
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










