
拿来即用 Java 企业级工具类全家桶-60-ZIP压缩解压工具类 目录一、工具类功能二、所需环境三、方法概览按需调用四、调用示例直观体验五、工具类源码可直接复制一、工具类功能把多个文件或目录递归打包成一个 zip、把 zip 安全解压到指定目录、解压前先把条目名清点一遍中文条目名按 UTF-8 写旧版 Windows 打的包可按 GBK 读。拿回来的是解压出的文件条目数和按包内顺序排列的条目名清单。解压自带 Zip Slip 与压缩炸弹双上限防护不重建符号链接与 POSIX 权限落盘时间取解压时刻。二、所需环境JDK 17或以上三、方法概览按需调用序号方法入参返回用途1zip(zipFile, sources…)输出zip路径 待压缩源文件或目录可多个void默认压缩级别把多个文件与目录递归打成一个包2zip(zipFile, compressionLevel, sources…)输出zip路径 压缩级别 待压缩源可多个void指定压缩级别打包0 仅存储、9 最高3unzip(zipFile, targetDir)zip路径 解压目标目录int按 UTF-8 条目名解压用默认安全上限4unzip(zipFile, targetDir, charset)zip路径 解压目标目录 条目名编码int指定条目名编码解压上限用默认值5unzip(zipFile, targetDir, charset, maxEntries, maxTotalBytes)zip路径 解压目标目录 条目名编码 条目数上限 累计字节上限int收紧安全上限再解压防压缩炸弹6listEntries(zipFile)zip路径List解压前清点条目名保持包内顺序7listEntries(zipFile, charset)zip路径 条目名编码List按指定编码清点条目名四、调用示例直观体验调用示例直接复制进 IDE 右键 Run 就能看到调用工具类各方法的输出结果。21:00:32.431[main]INFO--「ZipUtils方法1zip(zipFile,sources...)」目录与文件一起打包包大小-457字节21:00:32.443[main]INFO--「ZipUtils方法2zip(zipFile,compressionLevel,sources...)」级别0仅存储包大小-166字节21:00:32.468[main]INFO--「ZipUtils方法3unzip(zipFile,targetDir)」返回文件条目数-2还原出的文件-[报表/月度报表.txt,说明.txt]21:00:32.490[main]INFO--「ZipUtils方法4unzip(zipFile,targetDir,charset)」按GBK解旧包返回文件条目数-1还原出的文件-[中文清单.txt]21:00:32.496[main]INFO--「ZipUtils方法5unzip(zipFile,targetDir,charset,maxEntries,maxTotalBytes)」上限放到10个条目与1MiB返回文件条目数-221:00:32.497[main]INFO--「ZipUtils方法6listEntries(zipFile)」按包内顺序返回条目名-[报表/,报表/月度报表.txt,说明.txt]21:00:32.497[main]INFO--「ZipUtils方法7listEntries(zipFile,charset)」按GBK清点旧包条目名-[中文清单.txt]21:00:32.510[main]ERROR--「异常信息获取演示」文件不是zip-不是合法的zip文件(缺少zip文件头):C:\Users\zz\AppData\Local\Temp\zip-utils-demo16868942626655364350\不是zip.txt21:00:32.530[main]ERROR--「异常信息获取演示」条目名穿越目标目录-检测到非法zip条目(路径穿越):../逃出去.txt21:00:32.533[main]ERROR--「异常信息获取演示」条目数超上限-zip条目数超过上限1疑似压缩炸弹21:00:32.533[main]ERROR--「异常信息获取演示」GBK包按UTF-8读-zip条目名无法按UTF-8解码该包的条目名可能是别的编码旧版Windows打的包传GBK:malformed input off:1,length:1进程已结束退出代码为0packagecom.example.order.api;importcom.example.common.utils.ZipUtils;importlombok.extern.slf4j.Slf4j;importjava.io.IOException;importjava.io.OutputStream;importjava.nio.charset.Charset;importjava.nio.charset.StandardCharsets;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.StandardOpenOption;importjava.util.ArrayList;importjava.util.Comparator;importjava.util.List;importjava.util.zip.ZipEntry;importjava.util.zip.ZipOutputStream;/** * 调用示例整个文件复制进 IDE右键 Run 就能看效果。 * * p压缩解压只依赖 JDK 自带的 {code java.util.zip}不依赖外部服务也不需要 Spring 容器 * 示例在系统临时目录里现造「一个目录 一个文件」的源数据打包、还原、清点条目跑完自删。 * 日志用 Lombok 的 {code Slf4j} SLF4J 占位符没装 Lombok 就把 {code log} 换成项目自己的 Logger。 */Slf4jpublicclassZipUtilsDemo{/** 旧版 Windows 自带工具打的包用 GBK 存条目名 */privatestaticfinalCharsetGBKCharset.forName(GBK);publicstaticvoidmain(String[]args)throwsIOException{PathdirFiles.createTempDirectory(zip-utils-demo);try{PathreportFilewrite(dir.resolve(报表/月度报表.txt),本月营业额 12800 元);Pathnoteswrite(dir.resolve(说明.txt),hello zip);Pathzipdir.resolve(出账.zip);// 一、压缩 ZipUtils.zip(zip,reportFile.getParent(),notes);log.info(「ZipUtils 方法1 zip(zipFile, sources...)」目录与文件一起打包包大小 - {} 字节,Files.size(zip));Pathstoreddir.resolve(仅存储.zip);ZipUtils.zip(stored,0,notes);log.info(「ZipUtils 方法2 zip(zipFile, compressionLevel, sources...)」级别 0 仅存储包大小 - {} 字节,Files.size(stored));// 二、解压 Pathrestoreddir.resolve(还原);intfileCountZipUtils.unzip(zip,restored);log.info(「ZipUtils 方法3 unzip(zipFile, targetDir)」返回文件条目数 - {}还原出的文件 - {},fileCount,listed(restored));PathgbkZipdir.resolve(旧包.zip);buildZip(gbkZip,GBK,中文清单.txt,GBK 存的条目名);PathgbkRestoreddir.resolve(还原GBK);log.info(「ZipUtils 方法4 unzip(zipFile, targetDir, charset)」按 GBK 解旧包返回文件条目数 - {}还原出的文件 - {},ZipUtils.unzip(gbkZip,gbkRestored,GBK),listed(gbkRestored));Pathcappeddir.resolve(限量还原);log.info(「ZipUtils 方法5 unzip(zipFile, targetDir, charset, maxEntries, maxTotalBytes)」上限放到 10 个条目与 1MiB返回文件条目数 - {},ZipUtils.unzip(zip,capped,StandardCharsets.UTF_8,10,1024*1024));// 三、清点条目 log.info(「ZipUtils 方法6 listEntries(zipFile)」按包内顺序返回条目名 - {},ZipUtils.listEntries(zip));log.info(「ZipUtils 方法7 listEntries(zipFile, charset)」按 GBK 清点旧包条目名 - {},ZipUtils.listEntries(gbkZip,GBK));// 四、catch异常信息 // 1. 内容根本不是 zip先查文件头不会当成空包静返回 0Pathfakewrite(dir.resolve(不是zip.txt),just text, not a zip);try{ZipUtils.unzip(fake,dir.resolve(不该建目录));}catch(IllegalArgumentExceptione){log.error(「异常信息获取演示」文件不是zip - {},e.getMessage());}// 2. Zip Slip条目名想跳出目标目录直接拒绝且不落盘Pathevildir.resolve(穿越包.zip);buildZip(evil,StandardCharsets.UTF_8,../逃出去.txt,boom);try{ZipUtils.unzip(evil,dir.resolve(穿越目标));}catch(IllegalStateExceptione){log.error(「异常信息获取演示」条目名穿越目标目录 - {},e.getMessage());}// 3. 压缩炸弹防护条目数上限收紧到 1第二个条目就拦住try{ZipUtils.unzip(zip,dir.resolve(限量失败),StandardCharsets.UTF_8,1,1024*1024);}catch(IllegalStateExceptione){log.error(「异常信息获取演示」条目数超上限 - {},e.getMessage());}// 4. 条目名编码给错明确报解码失败并提示换编码不写出乱码文件名try{ZipUtils.listEntries(gbkZip);}catch(IllegalArgumentExceptione){log.error(「异常信息获取演示」GBK 包按 UTF-8 读 - {},e.getMessage());}}finally{deleteQuietly(dir);}}/** 写出一个文件父目录自动建好返回它本身或它所在的目录 */privatestaticPathwrite(Pathfile,Stringcontent)throwsIOException{Files.createDirectories(file.getParent());Files.writeString(file,content,StandardCharsets.UTF_8);returnfile;}/** 手工做一个指定编码、指定条目名的 zip用来演示 GBK 旧包与恶意条目名 */privatestaticvoidbuildZip(Pathzip,Charsetcharset,StringentryName,Stringcontent)throwsIOException{Files.createDirectories(zip.getParent());try(OutputStreamoutFiles.newOutputStream(zip,StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING);ZipOutputStreamzosnewZipOutputStream(out,charset)){zos.putNextEntry(newZipEntry(entryName));zos.write(content.getBytes(StandardCharsets.UTF_8));zos.closeEntry();}}/** 列出目录下全部文件的相对路径统一写成斜杠验证解压出的结构 */privatestaticListStringlisted(Pathdir)throwsIOException{ListStringnamesnewArrayList();try(varpathsFiles.walk(dir)){paths.filter(Files::isRegularFile).sorted().forEach(path-names.add(dir.relativize(path).toString().replace(java.io.File.separatorChar,/)));}returnnames;}/** 递归删除临时目录与其中的文件先删文件后删目录 */privatestaticvoiddeleteQuietly(Pathdir)throwsIOException{try(varpathsFiles.walk(dir)){paths.sorted(Comparator.reverseOrder()).forEach(path-{try{Files.deleteIfExists(path);}catch(IOExceptionignored){// 临时文件删不掉也不影响示例结论}});}}}五、工具类源码可直接复制 「点击此处可下载 Java企业级工具类全家桶-60-ZIP压缩解压工具类」 的完整源码拿来即用。觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~