Java利用ZipOutputStream進(jìn)行高效壓縮的技巧詳解
簡介
ZipOutputStream 是 Java 標(biāo)準(zhǔn)庫中用于 創(chuàng)建 ZIP 文件 的核心類,位于 java.util.zip 包中。它允許你將多個文件或字節(jié)流寫入一個 ZIP 壓縮包,并支持設(shè)置壓縮級別、編碼方式等參數(shù)。
基本概念
ZipOutputStream的作用
- 將多個文件(或字節(jié)數(shù)組)打包成一個 ZIP 文件。
- 支持添加多個條目(
ZipEntry),每個條目代表 ZIP 中的一個文件。 - 可控制壓縮級別、編碼格式、注釋等。
常用方法說明
| 方法 | 描述 |
|---|---|
| putNextEntry(ZipEntry entry) | 開始寫入一個新的 ZIP 條目(文件) |
| closeEntry() | 關(guān)閉當(dāng)前 ZIP 條目,準(zhǔn)備寫入下一個 |
| write(byte[] b, int off, int len) | 寫入當(dāng)前條目的內(nèi)容(字節(jié)數(shù)據(jù)) |
| setLevel(int level) | 設(shè)置壓縮級別(0~9) |
| setComment(String comment) | 設(shè)置整個 ZIP 文件的注釋 |
| finish() | 完成寫入,但不關(guān)閉底層輸出流(可選) |
可選的壓縮級別(取值范圍:0 ~ 9)
| 級別 | 含義 | 特點(diǎn) |
|---|---|---|
| Deflater.NO_COMPRESSION (0) | 不壓縮 | 速度最快,ZIP 文件最大 |
| Deflater.BEST_SPEED (1) | 最快壓縮 | 壓縮率低,速度快 |
| Deflater.DEFAULT_COMPRESSION (6) | 默認(rèn)壓縮 | 平衡壓縮率與速度 |
| 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 自動關(guān)閉資源(FileOutputStream 和 ZipOutputStream)
try (FileOutputStream fos = new FileOutputStream(zipFilePath);
ZipOutputStream zos = new ZipOutputStream(fos)) {
// 設(shè)置 ZIP 壓縮級別為最佳壓縮(壓縮率最高,但速度較慢)
zos.setLevel(Deflater.BEST_COMPRESSION);
// 遍歷源目錄下的所有文件(包括子目錄中的文件)
Files.walk(Paths.get(sourceDir))
// 過濾掉目錄,只保留文件
.filter(path -> !Files.isDirectory(path))
// 對每個文件執(zhí)行以下操作
.forEach(path -> {
try {
// 構(gòu)建相對路徑字符串:sourceDir + 文件分隔符 + 文件名
// 注意:這會導(dǎo)致 ZIP 中的路徑包含 sourceDir 的前綴
String relativePath = sourceDir + File.separator + path.getFileName();
// 創(chuàng)建一個 ZIP 條目(即 ZIP 包中的一個文件)
ZipEntry zipEntry = new ZipEntry(relativePath);
// 開始寫入該條目到 ZIP 流中
zos.putNextEntry(zipEntry);
// 讀取文件內(nèi)容為字節(jié)數(shù)組
byte[] bytes = Files.readAllBytes(path);
// 將文件內(nèi)容寫入 ZIP 輸出流
zos.write(bytes, 0, bytes.length);
// 關(guān)閉當(dāng)前 ZIP 條目,準(zhǔn)備寫入下一個文件
zos.closeEntry();
} catch (IOException e) {
// 如果寫入失敗,打印錯誤信息并輸出異常堆棧
System.err.println("寫入 ZIP 失敗: " + path);
e.printStackTrace();
}
});
}
// try-with-resources 會自動關(guān)閉 fos 和 zos,無需手動 close()
}
}
ZIP 文件網(wǎng)絡(luò)流下載
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("導(dǎo)出 ZIP 異常", ex);
throw new RuntimeException("導(dǎo)出異常");
}
1. 設(shè)置響應(yīng)頭
response.setContentType("application/zip");
- 設(shè)置 HTTP 響應(yīng)內(nèi)容類型為
application/zip,告訴瀏覽器這是一個 ZIP 文件。 - 瀏覽器收到后會識別為壓縮文件,通常會觸發(fā)下載行為。
response.setHeader("Content-Disposition", "attachment; filename=\"streamed_files.zip\"");
- 設(shè)置響應(yīng)頭
Content-Disposition,值為attachment表示讓瀏覽器不要在頁面中顯示該內(nèi)容,而是提示用戶下載。 filename="streamed_files.zip"指定下載時的默認(rèn)文件名。
2. 創(chuàng)建 ZIP 輸出流(使用 try-with-resources)
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) {
- 使用
try-with-resources自動關(guān)閉資源,確保最后流會被正確關(guān)閉。 - 創(chuàng)建了一個
ZipOutputStream,它是一個用于寫入 ZIP 文件格式的輸出流。 - 第二個參數(shù)
StandardCharsets.UTF_8是為了支持中文文件名編碼(避免解壓時出現(xiàn)亂碼)。
注意:部分舊系統(tǒng)或工具(如 Windows 自帶解壓器)可能不識別 UTF-8 編碼的 ZIP 文件名,建議使用 7-Zip、WinRAR 或 Mac 解壓工具。
3. 設(shè)置壓縮級別(可選)
zipOut.setLevel(Deflater.BEST_SPEED);
- 設(shè)置壓縮級別為最快壓縮模式。
- 這樣可以減少服務(wù)器 CPU 占用,適合對壓縮率要求不高但希望快速響應(yīng)用戶的場景。
- 可替換為:
Deflater.DEFAULT_COMPRESSION(默認(rèn))Deflater.BEST_COMPRESSION(最佳壓縮)
4. 生成文件加入到 zip 流
zipOut.putNextEntry(new ZipEntry(fileName));
- 在 ZIP 包中創(chuàng)建一個新的條目(即文件),名字是上面生成的文件名。
- 每次調(diào)用
putNextEntry()后必須調(diào)用closeEntry()才能繼續(xù)添加下一個文件。
byte[] docBytes = genDocx(u).toByteArray(); zipOut.write(docBytes, 0, docBytes.length);
- 調(diào)用
genDocx(u)方法生成當(dāng)前用戶的.docx文件內(nèi)容(返回的是ByteArrayOutputStream)。 - 將其轉(zhuǎn)為字節(jié)數(shù)組后寫入 ZIP 流中。
zipOut.closeEntry();
關(guān)閉當(dāng)前 ZIP 條目,準(zhǔn)備寫入下一個文件。
到此這篇關(guān)于Java利用ZipOutputStream進(jìn)行高效壓縮的技巧詳解的文章就介紹到這了,更多相關(guān)Java ZipOutputStream壓縮內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java ==,equals()與hashcode()的使用
本文主要介紹了Java ==,equals()與hashcode()的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
spring boot 配置freemarker及如何使用freemarker渲染頁面
springboot中自帶的頁面渲染工具為thymeleaf 還有freemarker這兩種模板引擎,本文重點(diǎn)給大家介紹spring boot 配置freemarker及如何使用freemarker渲染頁面,感興趣的朋友一起看看吧2023-10-10
Java類之間的關(guān)系圖_動力節(jié)點(diǎn)Java學(xué)院整理
在Java以及其他的面向?qū)ο笤O(shè)計模式中,類與類之間主要有6種關(guān)系,他們分別是:依賴、關(guān)聯(lián)、聚合、組合、繼承、實現(xiàn)。他們的耦合度依次增強(qiáng),有興趣的可以了解一下2017-08-08
解決Springboot項目報錯:java:錯誤:不支持發(fā)行版本?17
這篇文章主要給大家介紹了關(guān)于解決Springboot項目報錯:java:錯誤:不支持發(fā)行版本17的相關(guān)資料,這個錯誤意味著你的Spring Boot項目正在使用Java 17這個版本,但是你的項目中未配置正確的Java版本,需要的朋友可以參考下2023-08-08
6種常見的SpringBoot攔截器使用場景及實現(xiàn)方式
這篇文章主要為大家詳細(xì)介紹了SpringBoot中6種常見的攔截器使用場景及其實現(xiàn)方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04

