Java利用ZipOutputStream进行高效压缩的技巧详解
作者:心之语歌
ZipOutputStream 是 Java 标准库中用于 创建 ZIP 文件 的核心类,位于 java.util.zip 包中,本文主要和大家介绍了Java如何使用ZipOutputStream进行高效压缩,有需要的可以了解下
简介
ZipOutputStream 是 Java 标准库中用于 创建 ZIP 文件 的核心类,位于 java.util.zip 包中。它允许你将多个文件或字节流写入一个 ZIP 压缩包,并支持设置压缩级别、编码方式等参数。
基本概念
ZipOutputStream的作用
- 将多个文件(或字节数组)打包成一个 ZIP 文件。
- 支持添加多个条目(
ZipEntry),每个条目代表 ZIP 中的一个文件。 - 可控制压缩级别、编码格式、注释等。
常用方法说明
| 方法 | 描述 |
|---|---|
| putNextEntry(ZipEntry entry) | 开始写入一个新的 ZIP 条目(文件) |
| closeEntry() | 关闭当前 ZIP 条目,准备写入下一个 |
| write(byte[] b, int off, int len) | 写入当前条目的内容(字节数据) |
| setLevel(int level) | 设置压缩级别(0~9) |
| setComment(String comment) | 设置整个 ZIP 文件的注释 |
| finish() | 完成写入,但不关闭底层输出流(可选) |
可选的压缩级别(取值范围:0 ~ 9)
| 级别 | 含义 | 特点 |
|---|---|---|
| Deflater.NO_COMPRESSION (0) | 不压缩 | 速度最快,ZIP 文件最大 |
| Deflater.BEST_SPEED (1) | 最快压缩 | 压缩率低,速度快 |
| Deflater.DEFAULT_COMPRESSION (6) | 默认压缩 | 平衡压缩率与速度 |
| Deflater.BEST_COMPRESSION (9) | 最佳压缩 | 压缩率最高,速度最慢 |
本地保存
import java.io.*;
import java.nio.file.*;
import java.util.zip.*;
public class ZipDemo {
public static void main(String[] args) throws IOException {
// 源文件夹路径:要压缩的文件所在的目录
String sourceDir = "path/to/folder";
// 输出 ZIP 文件路径:生成的压缩包保存的位置和名称
String zipFilePath = "output.zip";
// 使用 try-with-resources 自动关闭资源(FileOutputStream 和 ZipOutputStream)
try (FileOutputStream fos = new FileOutputStream(zipFilePath);
ZipOutputStream zos = new ZipOutputStream(fos)) {
// 设置 ZIP 压缩级别为最佳压缩(压缩率最高,但速度较慢)
zos.setLevel(Deflater.BEST_COMPRESSION);
// 遍历源目录下的所有文件(包括子目录中的文件)
Files.walk(Paths.get(sourceDir))
// 过滤掉目录,只保留文件
.filter(path -> !Files.isDirectory(path))
// 对每个文件执行以下操作
.forEach(path -> {
try {
// 构建相对路径字符串:sourceDir + 文件分隔符 + 文件名
// 注意:这会导致 ZIP 中的路径包含 sourceDir 的前缀
String relativePath = sourceDir + File.separator + path.getFileName();
// 创建一个 ZIP 条目(即 ZIP 包中的一个文件)
ZipEntry zipEntry = new ZipEntry(relativePath);
// 开始写入该条目到 ZIP 流中
zos.putNextEntry(zipEntry);
// 读取文件内容为字节数组
byte[] bytes = Files.readAllBytes(path);
// 将文件内容写入 ZIP 输出流
zos.write(bytes, 0, bytes.length);
// 关闭当前 ZIP 条目,准备写入下一个文件
zos.closeEntry();
} catch (IOException e) {
// 如果写入失败,打印错误信息并输出异常堆栈
System.err.println("写入 ZIP 失败: " + path);
e.printStackTrace();
}
});
}
// try-with-resources 会自动关闭 fos 和 zos,无需手动 close()
}
}
ZIP 文件网络流下载
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"streamed_files.zip\"");
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) {
zipOut.setLevel(Deflater.BEST_SPEED);
for (User u : userList) {
String fileName = String.format("%sxxxx.docx", u.getNickName());
try {
zipOut.putNextEntry(new ZipEntry(fileName));
byte[] docBytes = genDocx(u).toByteArray();
zipOut.write(docBytes, 0, docBytes.length);
zipOut.closeEntry();
} catch (IOException e) {
log.error("写入 ZIP 条目失败: {}", fileName, e);
throw new IOException("生成 ZIP 条目时出错: " + fileName, e);
}
}
} catch (IOException ex) {
log.error("导出 ZIP 异常", ex);
throw new RuntimeException("导出异常");
}
1. 设置响应头
response.setContentType("application/zip");
- 设置 HTTP 响应内容类型为
application/zip,告诉浏览器这是一个 ZIP 文件。 - 浏览器收到后会识别为压缩文件,通常会触发下载行为。
response.setHeader("Content-Disposition", "attachment; filename=\"streamed_files.zip\"");
- 设置响应头
Content-Disposition,值为attachment表示让浏览器不要在页面中显示该内容,而是提示用户下载。 filename="streamed_files.zip"指定下载时的默认文件名。
2. 创建 ZIP 输出流(使用 try-with-resources)
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) {
- 使用
try-with-resources自动关闭资源,确保最后流会被正确关闭。 - 创建了一个
ZipOutputStream,它是一个用于写入 ZIP 文件格式的输出流。 - 第二个参数
StandardCharsets.UTF_8是为了支持中文文件名编码(避免解压时出现乱码)。
注意:部分旧系统或工具(如 Windows 自带解压器)可能不识别 UTF-8 编码的 ZIP 文件名,建议使用 7-Zip、WinRAR 或 Mac 解压工具。
3. 设置压缩级别(可选)
zipOut.setLevel(Deflater.BEST_SPEED);
- 设置压缩级别为最快压缩模式。
- 这样可以减少服务器 CPU 占用,适合对压缩率要求不高但希望快速响应用户的场景。
- 可替换为:
Deflater.DEFAULT_COMPRESSION(默认)Deflater.BEST_COMPRESSION(最佳压缩)
4. 生成文件加入到 zip 流
zipOut.putNextEntry(new ZipEntry(fileName));
- 在 ZIP 包中创建一个新的条目(即文件),名字是上面生成的文件名。
- 每次调用
putNextEntry()后必须调用closeEntry()才能继续添加下一个文件。
byte[] docBytes = genDocx(u).toByteArray(); zipOut.write(docBytes, 0, docBytes.length);
- 调用
genDocx(u)方法生成当前用户的.docx文件内容(返回的是ByteArrayOutputStream)。 - 将其转为字节数组后写入 ZIP 流中。
zipOut.closeEntry();
关闭当前 ZIP 条目,准备写入下一个文件。
到此这篇关于Java利用ZipOutputStream进行高效压缩的技巧详解的文章就介绍到这了,更多相关Java ZipOutputStream压缩内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
