java.util.zip
包处理压缩文件:通过ZipInputStream
或ZipFile
读取压缩包,遍历内部条目(ZipEntry
),对每个文件条目获取输入流并读取数据,最后解压到目标路径或进行内存操作。在Java中处理压缩包(如ZIP文件)需要用到java.util.zip
包提供的API,以下是详细的操作步骤和代码示例,涵盖文件读取、解压和安全注意事项:
核心步骤
-
创建ZipInputStream
通过ZipInputStream
读取压缩包,关联文件输入流:try (ZipInputStream zis = new ZipInputStream(new FileInputStream("example.zip"))) { // 处理压缩包内容 }
-
遍历压缩条目
使用getNextEntry()
逐个获取压缩包内的文件/目录:ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { String entryName = entry.getName(); // 获取文件名 // 处理当前条目 }
-
提取文件内容
读取条目数据并写入目标文件:Path outputPath = Paths.get("解压目录/" + entryName); Files.createDirectories(outputPath.getParent()); // 创建父目录 Files.copy(zis, outputPath); // 复制文件内容
-
关闭资源
使用try-with-resources自动关闭流(推荐)。
完整代码示例
import java.io.*; import java.nio.file.*; import java.util.zip.*; public class UnzipExample { public static void main(String[] args) { String zipFile = "archive.zip"; String outputDir = "uncompressed/"; try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) { ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { Path outputPath = Paths.get(outputDir + entry.getName()); // 跳过目录条目(部分ZIP工具会显式创建目录) if (entry.isDirectory()) { Files.createDirectories(outputPath); continue; } // 确保父目录存在 Files.createDirectories(outputPath.getParent()); // 写入文件 Files.copy(zis, outputPath, StandardCopyOption.REPLACE_EXISTING); } System.out.println("解压完成!"); } catch (IOException e) { e.printStackTrace(); } } }
关键注意事项
-
路径安全
- 验证条目名称:防止路径穿越攻击(如恶意路径)
if (entry.getName().contains("..")) { throw new SecurityException("非法路径: " + entry.getName()); }
- 验证条目名称:防止路径穿越攻击(如恶意路径)
-
大文件处理
使用缓冲区逐块读取(替代Files.copy
):try (OutputStream os = Files.newOutputStream(outputPath)) { byte[] buffer = new byte[4096]; int len; while ((len = zis.read(buffer)) > 0) { os.write(buffer, 0, len); } }
-
字符编码问题
中文文件名乱码时指定编码:new ZipInputStream(new FileInputStream(zipFile), Charset.forName("GBK"));
-
异常处理
捕获常见异常:ZipException
: 压缩包损坏或格式错误SecurityException
: 文件权限不足FileNotFoundException
: 压缩包不存在
高级场景
-
读取特定文件
不解压整个包,直接读取目标文件:try (ZipFile zip = new ZipFile("archive.zip")) { ZipEntry entry = zip.getEntry("config.txt"); try (InputStream is = zip.getInputStream(entry)) { // 读取文件内容 } }
-
内存中处理
解压到字节数组(适用于非持久化操作):ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = zis.read(buffer)) > 0) { baos.write(buffer, 0, len); } byte[] fileData = baos.toByteArray();
最佳实践
- 验证压缩来源:用户上传的压缩包需进行病毒扫描。
- 资源释放:确保在finally块或try-with-resources中关闭流。
- 性能优化:大压缩包使用
ZipFile
(随机访问)替代ZipInputStream
(顺序读取)。 - 依赖库:复杂需求推荐使用Apache Commons Compress,支持更多压缩格式(7z、tar等)。
引用说明:本文代码基于Oracle官方Java API文档实现,安全建议参考OWASP路径遍历防护指南,第三方库信息来自Apache基金会官网。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/34724.html