Java將文件壓縮成zip并下載
Java文件壓縮成zip并下載
使用jdk自帶的zip包下的類來(lái)實(shí)現(xiàn)壓縮
1.實(shí)體類
實(shí)體類主要是文件名和文件路徑(base64字符串),壓縮文件路徑時(shí)可以不使用類里的文件名。
import lombok.Data;
@Data
public class FileInfoDto {
/**文件名*/
private String fileName;
**文件路徑或base64字符串*/
private String file;
}
2.工具類
創(chuàng)建和刪除文件的方式來(lái)輔助壓縮,在創(chuàng)建一個(gè)zip文件時(shí),每個(gè)zipEntry代表zip文件中的一個(gè)項(xiàng),zipEntry的名稱在zip文件內(nèi)必須是唯一的,因?yàn)閦ip文件格式使用這些條目名稱作為查找鍵,來(lái)定位和提取存儲(chǔ)在zip中的文件。所以名稱相同時(shí)會(huì)拋出異常,我這里在調(diào)用前做了處理。
我省略了項(xiàng)目路徑的import,使用時(shí)導(dǎo)入自己的路徑即可。
import org.springframework.core.io.ClassPathResource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author xxx
* @date 2023/10/18 14:43
* @description:
*/
public class BaseZipUtils {
/**
* 使用給定的文件列表創(chuàng)建ZIP文件并將其發(fā)送到HTTP響應(yīng)。
*
* @param response HttpServletResponse
* @param fileList 文件列表
* @param title ZIP文件的標(biāo)題
* @param type 1-base64壓縮,2-url-壓縮
*/
public static void downZipFile(HttpServletResponse response, List<FileInfoDto> fileList, String title, Integer type) {
// 獲取模板路徑,并構(gòu)建ZIP文件的完整路徑。
String tempDirPath = getTemplatePath();
File zipFilePath = new File(tempDirPath, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "_" + title);
try {
if (1 == type) {
// 基于Base64編碼的文件創(chuàng)建ZIP文件。
zipFiles(fileList, zipFilePath);
} else {
zipFilesFromURLs(fileList, zipFilePath);
}
// 如果ZIP文件存在,將其發(fā)送到HTTP響應(yīng)。
if (zipFilePath.exists()) {
try (InputStream is = new FileInputStream(zipFilePath);
OutputStream os = response.getOutputStream()) {
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(zipFilePath.getName(), "UTF-8"));
// 從ZIP文件讀取內(nèi)容并寫(xiě)入HTTP響應(yīng)。
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
} finally {
// 刪除臨時(shí)ZIP文件。
Files.deleteIfExists(zipFilePath.toPath());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 將Base64編碼的文件列表壓縮為一個(gè)ZIP文件。
*
* @param srcFiles 需要壓縮的文件列表
* @param zipFile 生成的ZIP文件
*/
public static void zipFiles(List<FileInfoDto> srcFiles, File zipFile) throws IOException {
// 如果ZIP文件不存在,創(chuàng)建它。
if (!zipFile.exists()) {
Files.createFile(zipFile.toPath());
}
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
for (FileInfoDto fileInfo : srcFiles) {
// 解碼文件名。
String fileName = URLDecoder.decode(fileInfo.getFileName(), "UTF-8");
// 創(chuàng)建ZIP條目并添加到ZIP輸出流中。
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
// 將Base64編碼的文件內(nèi)容解碼為字節(jié)數(shù)組。
byte[] fileBytes = Base64.getDecoder().decode(fileInfo.getFile());
// 將字節(jié)數(shù)組寫(xiě)入ZIP文件。
zos.write(fileBytes);
zos.closeEntry();
}
}
}
/**
* 使用從URL獲取的文件列表創(chuàng)建ZIP文件。
*
* @param srcFilesURLs 需要壓縮的文件URL列表
* @param zipFile 生成的ZIP文件
*/
public static void zipFilesFromURLs(List<FileInfoDto> srcFilesURLs, File zipFile) throws IOException {
// 如果ZIP文件不存在,創(chuàng)建它。
if (!zipFile.exists()) {
Files.createFile(zipFile.toPath());
}
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
for (FileInfoDto dto : srcFilesURLs) {
URL url = new URL(dto.getFile());
// 獲取文件的文件名。
String fileName = Paths.get(url.getPath()).getFileName().toString();
// 創(chuàng)建ZIP條目并添加到ZIP輸出流中。
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
// 從URL讀取文件內(nèi)容。
try (InputStream is = url.openStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
// 將從URL讀取的內(nèi)容寫(xiě)入ZIP文件。
zos.write(buffer, 0, bytesRead);
}
}
zos.closeEntry();
}
}
}
/**
* 獲取類路徑的絕對(duì)地址。
*
* @return 類路徑的絕對(duì)地址
*/
public static String getTemplatePath() {
try {
String realPath = new ClassPathResource("").getURL().getPath();
return URLDecoder.decode(realPath, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}3.js接收blob
/**
* 處理Blob響應(yīng)并觸發(fā)瀏覽器下載。
* @param {Object} res - 包含頭信息和數(shù)據(jù)的響應(yīng)對(duì)象。
* @param {string} [name] - 下載文件的可選名稱。
* @param {string} [type2] - Blob的可選類型。
*/
export const handleBlob = (res, name, type2) => {
// 從提供的名稱或響應(yīng)頭中獲取文件名
const fileName = name || (res.headers['content-disposition'] &&
decodeURI(res.headers['content-disposition'])
.split('filename=')[1]);
// 從提供的type2或響應(yīng)頭中獲取類型
const type = type2 || res.headers['content-type'];
// 創(chuàng)建Blob對(duì)象
const blob = new Blob([res.data], { type });
// 觸發(fā)瀏覽器下載
const downloadElement = document.createElement('a');
downloadElement.href = window.URL.createObjectURL(blob);
downloadElement.download = fileName; // 設(shè)置下載文件的名稱
document.body.appendChild(downloadElement);
downloadElement.click();
document.body.removeChild(downloadElement);
}
4.調(diào)用
String title = "測(cè)試.zip"; BaseZipUtils.downZipFile(response, fileList, title,1);
調(diào)用結(jié)果:


Java中多目錄文件壓縮成zip
將多個(gè)文件打包到zip提供給用戶下載,抽離出來(lái)了一個(gè)工具類,支持單文件、多文件、按類型的多文件的壓縮和下載。
1.實(shí)體類
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @date 2022/5/25 15:11
* @description:
*/
@Data
public class ZipDto implements Serializable {
/**類型名稱/子目錄名稱*/
private String typeName;
/**文件路徑*/
private String fileUrl;
/**
* 分類型時(shí),集合有值
* 文件路徑集合
*/
private List<String> urlList;
}
2.工具類
主要方法:
- downZipListType: 允許用戶按類型將文件列表打包成zip文件進(jìn)行下載。
- downZipList: 提供批量下載功能,可以將多個(gè)文件一起打包成zip文件。
- downZipOne: 為單個(gè)文件提供下載功能,雖然是單個(gè)文件,但為了保持統(tǒng)一性,仍然會(huì)將其打包成zip格式。
刪除了項(xiàng)目敏感import,自行導(dǎo)入實(shí)體即可。
import cn.hutool.core.util.StrUtil;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @date 2023/10/18 17:32
* @description:
*/
@Slf4j
@UtilityClass
public class CustomOriZipUtils {
private static final String SUFFIX_ZIP = ".zip";
private static final String UNNAMED = "未命名";
/**
* 按類型批量下載。
*/
public static void downZipListType(List<ZipDto> list, String fileName, HttpServletRequest request, HttpServletResponse response) {
try (ZipOutputStream zos = createZipOutputStream(response, request, fileName)) {
for (ZipDto dto : list) {
writeToZipStream(dto.getUrlList(), zos, dto.getTypeName());
}
} catch (Exception e) {
log.error("創(chuàng)建zip文件出錯(cuò)", e);
}
}
/**
* 批量下載。
*/
public static void downZipList(List<ZipDto> list, String fileName, HttpServletRequest request, HttpServletResponse response) {
try (ZipOutputStream zos = createZipOutputStream(response, request,fileName)) {
for (ZipDto dto : list) {
writeToZipStream(Collections.singletonList(dto.getFileUrl()), zos, dto.getTypeName());
}
} catch (Exception e) {
log.error("創(chuàng)建zip文件出錯(cuò)", e);
}
}
/**
* 下載單個(gè)記錄。
*/
public void downZipOne(ZipDto dto, String fileName, HttpServletRequest request, HttpServletResponse response) {
try (ZipOutputStream zos = createZipOutputStream(response, request,fileName)) {
writeToZipStream(Collections.singletonList(dto.getFileUrl()), zos, dto.getTypeName());
} catch (Exception e) {
log.error("創(chuàng)建zip文件出錯(cuò)", e);
}
}
/**
* 為下載設(shè)置響應(yīng)。
*/
private void setResponse(HttpServletResponse response, HttpServletRequest request,String fileName) throws UnsupportedEncodingException {
if (StrUtil.isAllBlank(fileName)) {
fileName = LocalDate.now() + UNNAMED;
}
if (!fileName.endsWith(SUFFIX_ZIP)) {
fileName += SUFFIX_ZIP;
}
fileName = encodeFileName(request, fileName);
response.setHeader("Connection", "close");
response.setHeader("Content-Type", "application/octet-stream;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
}
/**
* 將URL寫(xiě)入zip流中。
*/
private static void writeToZipStream(List<String> urls, ZipOutputStream zos, String subDir) {
byte[] buffer = new byte[1024];
for (String url : urls) {
if (StrUtil.isNotBlank(url)) {
try (InputStream is = new URL(url).openStream()) {
String fileName = StrUtil.isAllBlank(subDir) ? getFileName(url) : subDir + "/" + getFileName(url);
zos.putNextEntry(new ZipEntry(fileName));
int length;
while ((length = is.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
} catch (Exception e) {
log.error("將文件 [{}] 寫(xiě)入zip時(shí)出錯(cuò)", url, e);
}
}
}
}
/**
* 根據(jù)瀏覽器類型編碼文件名。
*/
private static String encodeFileName(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
String userAgent = request.getHeader("USER-AGENT");
if (userAgent.contains("Firefox")) {
return new String(fileName.getBytes(), "ISO8859-1");
}
return URLEncoder.encode(fileName, "UTF-8");
}
/**
* 創(chuàng)建ZipOutputStream并設(shè)置響應(yīng)頭。
*/
private static ZipOutputStream createZipOutputStream(HttpServletResponse response,HttpServletRequest request, String fileName) throws IOException {
setResponse(response, request,fileName);
return new ZipOutputStream(response.getOutputStream());
}
/**
* 從url獲取文件名
* @param url
* @return
*/
public String getFileName(String url) {
return url.substring(url.lastIndexOf('/') + 1);
}
3.效果
多目錄文件壓縮下載:

單文件打包下載:

到此這篇關(guān)于Java將文件壓縮成zip并下載的文章就介紹到這了,更多相關(guān)Java文件壓縮內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java并發(fā)包之CopyOnWriteArrayList類的深入講解
這篇文章主要給大家介紹了關(guān)于Java并發(fā)包之CopyOnWriteArrayList類的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
一步步教你搭建Scala開(kāi)發(fā)環(huán)境(非常詳細(xì)!)
Scala是一門(mén)基于jvm的函數(shù)式的面向?qū)ο缶幊陶Z(yǔ)言,擁有比java更加簡(jiǎn)潔的語(yǔ)法,下面這篇文章主要給大家介紹了關(guān)于搭建Scala開(kāi)發(fā)環(huán)境的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
spring-data-jpa中findOne與getOne的區(qū)別說(shuō)明
這篇文章主要介紹了spring-data-jpa中findOne與getOne的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Java字符串?dāng)?shù)字左右補(bǔ)全0的四種方式
這篇文章主要給大家介紹了關(guān)于Java字符串?dāng)?shù)字左右補(bǔ)全0的四種方式,在編程中有時(shí)候我們需要對(duì)一個(gè)字符串進(jìn)行字符填充,以滿足某些特定的要求,其中補(bǔ)全0是一種常見(jiàn)的需求,需要的朋友可以參考下2023-08-08
SpringBoot集成Swagger3的實(shí)現(xiàn)
本文主要介紹了SpringBoot集成Swagger3的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
Java實(shí)現(xiàn)較大二進(jìn)制文件的讀、寫(xiě)方法
本篇文章主要介紹了Java實(shí)現(xiàn)較大二進(jìn)制文件的讀、寫(xiě)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
微信公眾號(hào)測(cè)試賬號(hào)自定義菜單的實(shí)例代碼
這篇文章主要介紹了微信公眾號(hào)測(cè)試賬號(hào)自定義菜單的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02

