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-04spring-data-jpa中findOne與getOne的區(qū)別說(shuō)明
這篇文章主要介紹了spring-data-jpa中findOne與getOne的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java字符串?dāng)?shù)字左右補(bǔ)全0的四種方式
這篇文章主要給大家介紹了關(guān)于Java字符串?dāng)?shù)字左右補(bǔ)全0的四種方式,在編程中有時(shí)候我們需要對(duì)一個(gè)字符串進(jìn)行字符填充,以滿足某些特定的要求,其中補(bǔ)全0是一種常見(jiàn)的需求,需要的朋友可以參考下2023-08-08SpringBoot集成Swagger3的實(shí)現(xiàn)
本文主要介紹了SpringBoot集成Swagger3的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12Java實(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