Java將文件壓縮成zip并下載
Java文件壓縮成zip并下載
使用jdk自帶的zip包下的類來實現(xiàn)壓縮
1.實體類
實體類主要是文件名和文件路徑(base64字符串),壓縮文件路徑時可以不使用類里的文件名。
import lombok.Data; @Data public class FileInfoDto { /**文件名*/ private String fileName; **文件路徑或base64字符串*/ private String file; }
2.工具類
創(chuàng)建和刪除文件的方式來輔助壓縮,在創(chuàng)建一個zip文件時,每個zipEntry代表zip文件中的一個項,zipEntry的名稱在zip文件內(nèi)必須是唯一的,因為zip文件格式使用這些條目名稱作為查找鍵,來定位和提取存儲在zip中的文件。所以名稱相同時會拋出異常,我這里在調(diào)用前做了處理。
我省略了項目路徑的import,使用時導入自己的路徑即可。
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響應。 * * @param response HttpServletResponse * @param fileList 文件列表 * @param title ZIP文件的標題 * @param type 1-base64壓縮,2-url-壓縮 */ public static void downZipFile(HttpServletResponse response, List<FileInfoDto> fileList, String title, Integer type) { // 獲取模板路徑,并構建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響應。 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)容并寫入HTTP響應。 byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } } finally { // 刪除臨時ZIP文件。 Files.deleteIfExists(zipFilePath.toPath()); } } } catch (Exception e) { e.printStackTrace(); } } /** * 將Base64編碼的文件列表壓縮為一個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ù)組寫入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)容寫入ZIP文件。 zos.write(buffer, 0, bytesRead); } } zos.closeEntry(); } } } /** * 獲取類路徑的絕對地址。 * * @return 類路徑的絕對地址 */ 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響應并觸發(fā)瀏覽器下載。 * @param {Object} res - 包含頭信息和數(shù)據(jù)的響應對象。 * @param {string} [name] - 下載文件的可選名稱。 * @param {string} [type2] - Blob的可選類型。 */ export const handleBlob = (res, name, type2) => { // 從提供的名稱或響應頭中獲取文件名 const fileName = name || (res.headers['content-disposition'] && decodeURI(res.headers['content-disposition']) .split('filename=')[1]); // 從提供的type2或響應頭中獲取類型 const type = type2 || res.headers['content-type']; // 創(chuàng)建Blob對象 const blob = new Blob([res.data], { type }); // 觸發(fā)瀏覽器下載 const downloadElement = document.createElement('a'); downloadElement.href = window.URL.createObjectURL(blob); downloadElement.download = fileName; // 設置下載文件的名稱 document.body.appendChild(downloadElement); downloadElement.click(); document.body.removeChild(downloadElement); }
4.調(diào)用
String title = "測試.zip"; BaseZipUtils.downZipFile(response, fileList, title,1);
調(diào)用結果:
Java中多目錄文件壓縮成zip
將多個文件打包到zip提供給用戶下載,抽離出來了一個工具類,支持單文件、多文件、按類型的多文件的壓縮和下載。
1.實體類
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; /** * 分類型時,集合有值 * 文件路徑集合 */ private List<String> urlList; }
2.工具類
主要方法:
- downZipListType: 允許用戶按類型將文件列表打包成zip文件進行下載。
- downZipList: 提供批量下載功能,可以將多個文件一起打包成zip文件。
- downZipOne: 為單個文件提供下載功能,雖然是單個文件,但為了保持統(tǒng)一性,仍然會將其打包成zip格式。
刪除了項目敏感import,自行導入實體即可。
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文件出錯", 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文件出錯", e); } } /** * 下載單個記錄。 */ 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文件出錯", e); } } /** * 為下載設置響應。 */ 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寫入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("將文件 [{}] 寫入zip時出錯", 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并設置響應頭。 */ 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.效果
多目錄文件壓縮下載:
單文件打包下載:
到此這篇關于Java將文件壓縮成zip并下載的文章就介紹到這了,更多相關Java文件壓縮內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java并發(fā)包之CopyOnWriteArrayList類的深入講解
這篇文章主要給大家介紹了關于Java并發(fā)包之CopyOnWriteArrayList類的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12一步步教你搭建Scala開發(fā)環(huán)境(非常詳細!)
Scala是一門基于jvm的函數(shù)式的面向對象編程語言,擁有比java更加簡潔的語法,下面這篇文章主要給大家介紹了關于搭建Scala開發(fā)環(huán)境的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-04-04spring-data-jpa中findOne與getOne的區(qū)別說明
這篇文章主要介紹了spring-data-jpa中findOne與getOne的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11