Java文件目錄下載并打包成ZIP壓縮包
在Java中如果要實(shí)現(xiàn)文件夾、文件目錄的遞歸下載并打包成ZIP壓縮包,可以通過(guò)以下步驟進(jìn)行:
遍歷文件夾:使用遞歸方法遍歷指定目錄下的所有文件和文件夾
創(chuàng)建ZIP輸出流:使用java.util.zip包中的ZipOutputStream類創(chuàng)建ZIP文件
將文件添加到ZIP:將遍歷到的文件逐個(gè)添加到ZIP壓縮包中
單個(gè)文件目錄打包ZIP下載
單個(gè)文件目錄打包ZIP下載與文件目錄遞歸打包ZIP下載類似,首先來(lái)看看單個(gè)文件目錄中的文件是如何打包ZIP下載的。
/**
* 下載指定文件夾及其所有文件的內(nèi)容,并將其打包為 ZIP 文件。
*
* @param folderId 需要下載的文件夾 ID
* @param response HTTP 響應(yīng)對(duì)象,用于發(fā)送 ZIP 文件
* @throws IOException 在處理輸入輸出時(shí)可能拋出異常
*/
public void downloadFolder(Integer folderId, HttpServletResponse response) throws IOException {
// 校驗(yàn)權(quán)限,檢查用戶是否有權(quán)限下載該文件夾
Boolean isAuth = checkAuthService.checkAuthDownload(folderId);
if (!isAuth) {
// 如果沒(méi)有權(quán)限,則拋出業(yè)務(wù)異常
throw new BusinessException(TipsConstant.Tips_6002);
}
// 查詢指定文件夾下的所有文件列表
List<FileOrg> fileOrgList = getFileBeansByFolderId(folderId);
// 獲取文件夾信息,用于設(shè)置 ZIP 文件的名稱
FolderOrg folderOrg = folderOrgMappr.selectById(folderId);
// 準(zhǔn)備壓縮文件的數(shù)據(jù)
try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
// 設(shè)置響應(yīng)頭,準(zhǔn)備發(fā)送 ZIP 文件
prepareResponse(response, folderOrg.getName());
// 將文件添加到 ZIP 壓縮包中
addFilesToZip(zipOutputStream, fileOrgList, folderOrg.getName());
} catch (IOException e) {
// 如果發(fā)生錯(cuò)誤,返回 500 錯(cuò)誤和錯(cuò)誤信息
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to download folder: " + e.getMessage());
}
}
這里首先假設(shè)有一個(gè)目錄:測(cè)試目錄,里面有文件與文件目錄。以下是針對(duì)單個(gè)文件目錄打包ZIP下載實(shí)現(xiàn)的一個(gè)效果截圖。

遞歸文件目錄打包ZIP下載
遞歸文件目錄打包ZIP下載相比單個(gè)文件目錄打包ZIP下載,無(wú)非是多了個(gè)遞歸文件目錄的操作。
@Override
public void recursiveDownload(Integer folderId, HttpServletResponse response) throws IOException {
// 校驗(yàn)權(quán)限,檢查用戶是否有權(quán)限下載該文件夾
Boolean isAuth = checkAuthService.checkAuthDownload(folderId);
if (!isAuth) {
// 如果沒(méi)有權(quán)限,則拋出業(yè)務(wù)異常
throw new BusinessException(TipsConstant.Tips_6002);
}
// 獲取文件夾信息,用于設(shè)置 ZIP 文件的名稱
FolderOrg folderOrg = folderOrgMappr.selectById(folderId);
// 準(zhǔn)備壓縮文件的數(shù)據(jù)
try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
// 設(shè)置響應(yīng)頭,準(zhǔn)備發(fā)送 ZIP 文件
prepareResponse(response, folderOrg.getName());
// 遞歸調(diào)用將子文件夾及其文件添加到 ZIP
addFolderToZip(zipOutputStream, folderId, folderOrg.getName());
} catch (IOException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to download folder: " + e.getMessage());
}
}
這里首先假設(shè)有一個(gè)目錄:測(cè)試目錄,里面有文件與嵌套文件目錄。以下是針對(duì)遞歸文件目錄打包ZIP下載實(shí)現(xiàn)的一個(gè)效果截圖。


設(shè)置響應(yīng)頭
基于上述代碼,實(shí)現(xiàn)響應(yīng)頭的設(shè)置方法。在準(zhǔn)備將文件打包成 ZIP 文件之前,需要設(shè)置 HTTP 響應(yīng)的相關(guān)信息,包括字符編碼、內(nèi)容類型和文件名稱。這將確保用戶在下載時(shí)能夠正確識(shí)別文件類型。
/**
* 準(zhǔn)備 HTTP 響應(yīng),設(shè)置響應(yīng)頭以便下載 ZIP 文件。
*
* @param response HTTP 響應(yīng)對(duì)象
* @param folderName 文件夾名稱,用于生成 ZIP 文件的名稱
* @throws IOException 在設(shè)置響應(yīng)頭時(shí)可能拋出異常
*/
private void prepareResponse(HttpServletResponse response, String folderName) throws IOException {
// 設(shè)置字符編碼
response.setCharacterEncoding("UTF-8");
// 設(shè)置下載文件的名稱,使用 URL 編碼以兼容特殊字符
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(folderName + ".zip", "UTF-8"));
// 設(shè)置內(nèi)容類型為 ZIP 文件
response.setContentType("application/zip");
}
遞歸添加文件夾及文件
基于上述代碼,實(shí)現(xiàn)addFolderToZip方法是實(shí)現(xiàn)遞歸的關(guān)鍵。它首先獲取當(dāng)前文件夾中的文件列表,然后將這些文件添加到ZIP中。接著,它會(huì)獲取當(dāng)前文件夾的所有子文件夾,并對(duì)每個(gè)子文件夾遞歸調(diào)用自身。
/**
* 遞歸處理文件夾及其子文件夾
* 1.首先獲取當(dāng)前文件夾的文件列表,并調(diào)用 addFilesToZip 方法將文件添加到 ZIP 中。
* 2.然后獲取當(dāng)前文件夾的子文件夾,并遞歸調(diào)用 addFolderToZip 方法處理每個(gè)子文件夾
* @param zipOutputStream ZipOutputStream
* @param folderId 文件夾ID
* @throws IOException IO異常
*/
private void addFolderToZip(ZipOutputStream zipOutputStream, Integer folderId, String parentFolderName) throws IOException {
// 獲取當(dāng)前文件夾的文件列表
List<FileOrg> fileOrgList = getFileBeansByFolderId(folderId);
// 將當(dāng)前文件夾的文件添加到 ZIP
addFilesToZip(zipOutputStream, fileOrgList,parentFolderName);
// 獲取當(dāng)前文件夾的子文件夾
List<FolderOrg> subFolders = getSubFoldersByFolderId(folderId);
for (FolderOrg subFolder : subFolders) {
// 遞歸調(diào)用將子文件夾及其文件列表添加到 ZIP
addFolderToZip(zipOutputStream, subFolder.getId(),parentFolderName + "/" + subFolder.getName());
}
}
獲取子文件目錄與文件列表
獲取子文件夾與文件列表需根據(jù)自身業(yè)務(wù)實(shí)現(xiàn),這里基于數(shù)據(jù)庫(kù)查詢子文件目錄,查詢文件目錄下的文件,同時(shí)又涉及了一些處理業(yè)務(wù)邏輯。
1.獲取當(dāng)前文件夾的所有子文件夾
/**
* 獲取指定文件夾下的所有子文件夾。
* @param folderId 文件夾ID
* @return List<FolderOrg>
*/
private List<FolderOrg> getSubFoldersByFolderId(Integer folderId) {
QueryWrapper<FolderOrg> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deleted",0).eq("parent_id", folderId);
List<FolderOrg> folderOrgs = folderOrgMappr.selectList(queryWrapper);
return folderOrgs;
}
2.獲取文件夾下的文件列表
/**
* 根據(jù)文件夾 ID 獲取該文件夾下的所有文件信息。
*
* @param folderId 文件夾 ID
* @return 文件組織列表,包含該文件夾下的所有文件信息
*/
private List<FileOrg> getFileBeansByFolderId(Integer folderId) {
// 創(chuàng)建查詢條件,查找該文件夾下的所有文件鏈接
QueryWrapper<FileLinkOrg> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("folder_id", folderId);
List<FileLinkOrg> fileLinkOrgList = fileLinkOrgMapper.selectList(queryWrapper1);
// 如果沒(méi)有文件,返回空列表
if (fileLinkOrgList.isEmpty()) {
return new ArrayList<FileOrg>(0);
}
// 創(chuàng)建文件 ID 和名稱的映射關(guān)系
HashMap<String, String> fileNameMap = new HashMap<>();
fileLinkOrgList.forEach(item -> fileNameMap.put(item.getFileId(), item.getFileName()));
// 獲取文件夾下所有文件的 ID
ArrayList<String> fileIdList = new ArrayList<>(fileLinkOrgList.size());
fileLinkOrgList.forEach(item -> fileIdList.add(item.getFileId()));
// 根據(jù)文件 ID 查詢文件存儲(chǔ)信息
QueryWrapper<FileOrg> queryWrapper2 = new QueryWrapper<>();
queryWrapper2.in("id", fileIdList);
List<FileOrg> fileOrgList = fileOrgMapper.selectList(queryWrapper2);
// 更新文件組織列表中的文件名稱
fileOrgList.forEach(item -> item.setFileName(fileNameMap.get(item.getId())));
return fileOrgList;
}
將文件添加到ZIP中
基于上述代碼,實(shí)現(xiàn)addFilesToZip方法。需要將查詢到的文件添加到 ZIP 輸出流中。使用 ZipOutputStream 類來(lái)處理 ZIP 文件的創(chuàng)建和寫(xiě)入。在寫(xiě)入每個(gè)文件時(shí),需要確保使用正確的路徑和名稱。
/**
* 將指定文件列表中的文件添加到 ZIP 輸出流中。
*
* @param zipOutputStream ZIP 輸出流
* @param fileOrgList 文件組織列表,包含待添加的文件信息
* @throws IOException 在處理輸入輸出時(shí)可能拋出異常
*/
private void addFilesToZip(ZipOutputStream zipOutputStream, List<FileOrg> fileOrgList,String parentFolderName) throws IOException {
// 遍歷文件列表,將每個(gè)文件添加到 ZIP
for (FileOrg fileOrg : fileOrgList) {
try (InputStream inputStream = minioUtils.getObject(fileOrg.getBucketName(), fileOrg.getFilePath())) {
// 設(shè)置 ZIP 條目的路徑,包括文件夾名稱
String zipEntryName = parentFolderName + "/" + fileOrg.getFileName();
// 創(chuàng)建 ZIP 條目,使用文件名稱
zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
byte[] buffer = new byte[2048];
int length;
// 讀取文件內(nèi)容并寫(xiě)入 ZIP 輸出流
while ((length = inputStream.read(buffer)) > 0) {
zipOutputStream.write(buffer, 0, length);
}
// 關(guān)閉當(dāng)前 ZIP 條目
zipOutputStream.closeEntry();
} catch (Exception e) {
// 記錄異常信息,繼續(xù)處理其他文件
log.info("-------------------- 打包ZIP下載異常: {}--------------------", e.getMessage());
}
}
}
到此這篇關(guān)于Java文件目錄下載并打包成ZIP壓縮包的文章就介紹到這了,更多相關(guān)Java文件目錄下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java語(yǔ)言描述存儲(chǔ)結(jié)構(gòu)與鄰接矩陣代碼示例
這篇文章主要介紹了Java語(yǔ)言描述存儲(chǔ)結(jié)構(gòu)與鄰接矩陣代碼示例,涉及Java存儲(chǔ)結(jié)構(gòu),鄰接矩陣,鄰接表的介紹與比較,然后分享了鄰接矩陣的Java實(shí)現(xiàn)等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考。2017-11-11
SSH框架實(shí)現(xiàn)表單上傳圖片實(shí)例代碼
本篇文章主要介紹了SSH框架實(shí)現(xiàn)表單上傳圖片實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
MyBatis-Plus條件構(gòu)造器Wrapper應(yīng)用實(shí)例
QueryWrapper是用于查詢的Wrapper條件構(gòu)造器,可以通過(guò)它來(lái)構(gòu)建SELECT語(yǔ)句中的WHERE條件,這篇文章主要介紹了MyBatis-Plus數(shù)據(jù)表操作條件構(gòu)造器Wrapper,需要的朋友可以參考下2023-09-09
MyBatis動(dòng)態(tài)SQL實(shí)現(xiàn)配置過(guò)程解析
這篇文章主要介紹了MyBatis動(dòng)態(tài)SQL實(shí)現(xiàn)配置過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
Spring Security 單點(diǎn)登錄與自動(dòng)登錄機(jī)制的實(shí)現(xiàn)原理
本文探討SpringSecurity實(shí)現(xiàn)單點(diǎn)登錄(SSO)與自動(dòng)登錄機(jī)制,涵蓋JWT跨系統(tǒng)認(rèn)證、RememberMe持久化Token存儲(chǔ)、安全工具類及最佳實(shí)踐,強(qiáng)調(diào)安全性與性能平衡對(duì)提升用戶體驗(yàn)的重要性,感興趣的朋友一起看看吧2025-07-07

