Java实现打包压缩文件或文件夹生成zip以实现多文件批量下载

  • Java实现打包压缩文件或文件夹生成zip以实现多文件批量下载已关闭评论
  • 246 次浏览
  • A+
所属分类:Web前端
摘要

有时候在系统中需要一次性下载多个文件,但逐个下载文件比较麻烦。这时候,最好的解决办法是将所有文件打包成一个压缩文件,然后下载这个压缩文件,这样就可以一次性获取所有所需的文件了。

有时候在系统中需要一次性下载多个文件,但逐个下载文件比较麻烦。这时候,最好的解决办法是将所有文件打包成一个压缩文件,然后下载这个压缩文件,这样就可以一次性获取所有所需的文件了。

下面是一个名为CompressUtil的工具类的代码,它提供了一些方法来处理文件压缩和下载操作:

import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.lucene.util.RamUsageEstimator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.*; import java.util.zip.*;  /**  * @author fhey  * @date 2023-05-11 20:48:28  * @description: 压缩工具类  */  public class CompressUtil {      private static final Logger logger = LoggerFactory.getLogger(CompressUtil.class);      /**      * 将文件打包到zip并创建文件      *      * @param sourceFilePath      * @param zipFilePath      * @throws IOException      */     public static void createLocalCompressFile(String sourceFilePath, String zipFilePath) throws IOException {         createLocalCompressFile(sourceFilePath, zipFilePath, null);     }      /**      * 将文件打包到zip并创建文件      *      * @param sourceFilePath      * @param zipFilePath      * @param zipName      * @throws IOException      */     public static void createLocalCompressFile(String sourceFilePath, String zipFilePath, String zipName) throws IOException {         File sourceFile = new File(sourceFilePath);         if (!sourceFile.exists()) {             throw new RuntimeException(sourceFilePath + "不存在!");         }         if(StringUtils.isBlank(zipName)){             zipName = sourceFile.getName();         }         File zipFile = createNewFile(zipFilePath + File.separator + zipName + ".zip");         try (FileOutputStream fileOutputStream = new FileOutputStream(zipFile)) {             compressFile(sourceFile, fileOutputStream);         }     }      /**      * 获取压缩文件流      *      * @param sourceFilePath      * @return ByteArrayOutputStream      * @throws IOException      */     public static OutputStream compressFile(String sourceFilePath, OutputStream outputStream) throws IOException {         File sourceFile = new File(sourceFilePath);         if (!sourceFile.exists()) {             throw new RuntimeException(sourceFilePath + "不存在!");         }         return compressFile(sourceFile, outputStream);     }      /**      * 获取压缩文件流      *      * @param sourceFile      * @return ByteArrayOutputStream      * @throws IOException      */     private static OutputStream compressFile(File sourceFile, OutputStream outputStream) throws IOException {         try (CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream, new CRC32());              ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream)) {             doCompressFile(sourceFile, zipOutputStream, StringUtils.EMPTY);             return outputStream;         }     }      /**      * 处理目录下的文件      *      * @param sourceFile      * @param zipOutputStream      * @param zipFilePath      * @throws IOException      */     private static void doCompressFile(File sourceFile, ZipOutputStream zipOutputStream, String zipFilePath) throws IOException {         // 如果文件是隐藏的,不进行压缩         if (sourceFile.isHidden()) {             return;         }         if (sourceFile.isDirectory()) {//如果是文件夹             handDirectory(sourceFile, zipOutputStream, zipFilePath);         } else {//如果是文件就添加到压缩包中             try (FileInputStream fileInputStream = new FileInputStream(sourceFile)) {                 //String fileName = zipFilePath + File.separator + sourceFile.getName();                 String fileName = zipFilePath + sourceFile.getName();                 addCompressFile(fileInputStream, fileName, zipOutputStream);                 //String fileName = zipFilePath.replace("\", "/") + "/" + sourceFile.getName();                 //addCompressFile(fileInputStream, fileName, zipOutputStream);             }         }     }      /**      * 处理文件夹      *      * @param dir         文件夹      * @param zipOut      压缩包输出流      * @param zipFilePath 压缩包中的文件夹路径      * @throws IOException      */     private static void handDirectory(File dir, ZipOutputStream zipOut, String zipFilePath) throws IOException {         File[] files = dir.listFiles();         if (ArrayUtils.isEmpty(files)) {             ZipEntry zipEntry = new ZipEntry(zipFilePath + dir.getName() + File.separator);             zipOut.putNextEntry(zipEntry);             zipOut.closeEntry();             return;         }         for (File file : files) {             doCompressFile(file, zipOut, zipFilePath + dir.getName() + File.separator);         }     }      /**      * 获取压缩文件流      *      * @param documentList 需要压缩的文件集合      * @return ByteArrayOutputStream      */     public static OutputStream compressFile(List<FileInfo> documentList, OutputStream outputStream) {         Map<String, List<FileInfo>> documentMap = new HashMap<>();         documentMap.put("", documentList);         return compressFile(documentMap, outputStream);     }      /**      * 将文件打包到zip      *      * @param documentMap 需要下载的附件集合 map的key对应zip里的文件夹名      * @return ByteArrayOutputStream      */     public static OutputStream compressFile(Map<String, List<FileInfo>> documentMap, OutputStream outputStream) {         CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream, new CRC32());         ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream);         try {             for (Map.Entry<String, List<FileInfo>> documentListEntry : documentMap.entrySet()) {                 String dirName = documentMap.size() > 1 ? documentListEntry.getKey() : "";                 Map<String, Integer> fileNameToLen = new HashMap<>();//记录单个合同号文件夹下每个文件名称出现的次数(对重复文件名重命名)                 for (FileInfo document : documentListEntry.getValue()) {                     try {                         //防止单个文件夹下文件名重复 对重复的文件进行重命名                         String documentName = document.getFileName();                         if (fileNameToLen.get(documentName) == null) {                             fileNameToLen.put(documentName, 1);                         } else {                             int fileLen = fileNameToLen.get(documentName) + 1;                             fileNameToLen.put(documentName, fileLen);                             documentName = documentName + "(" + fileLen + ")";                         }                         String fileName = documentName + "." + document.getSuffix();                         if (StringUtils.isNotBlank(dirName)) {                             fileName = dirName + File.separator + fileName;                         }                         addCompressFile(document.getFileInputStream(), fileName, zipOutputStream);                     } catch (Exception e) {                         logger.info("filesToZip exception :", e);                     }                 }             }         } catch (Exception e) {             logger.error("filesToZip exception:" + e.getMessage(), e);         }         return outputStream;     }      /**      * 将单个文件写入文件压缩包      *      * @param inputStream     文件输入流      * @param fileName        文件在压缩包中的相对全路径      * @param zipOutputStream 压缩包输出流      */     private static void addCompressFile(InputStream inputStream, String fileName, ZipOutputStream zipOutputStream) {         try (BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {             ZipEntry zipEntry = new ZipEntry(fileName);             zipOutputStream.putNextEntry(zipEntry);             byte[] bytes = new byte[1024];             int length;             while ((length = bufferedInputStream.read(bytes)) >= 0) {                 zipOutputStream.write(bytes, 0, length);                 zipOutputStream.flush();             }             zipOutputStream.closeEntry();             //System.out.println("map size, value is " + RamUsageEstimator.sizeOf(zipOutputStream));         } catch (Exception e) {             logger.info("addFileToZip exception:", e);             throw new RuntimeException(e);         }     }      /**      * 通过网络请求下载zip      *      * @param sourceFilePath       需要压缩的文件路径      * @param response            HttpServletResponse      * @param zipName            压缩包名称      * @throws IOException      */     public static void httpDownloadCompressFile(String sourceFilePath, HttpServletResponse response, String zipName) throws IOException {         File sourceFile = new File(sourceFilePath);         if (!sourceFile.exists()) {             throw new RuntimeException(sourceFilePath + "不存在!");         }         if(StringUtils.isBlank(zipName)){             zipName = sourceFile.getName();         }         try (ServletOutputStream servletOutputStream = response.getOutputStream()){             CompressUtil.compressFile(sourceFile, servletOutputStream);             response.setContentType("application/zip");             response.setHeader("Content-Disposition", "attachment; filename="" + zipName + ".zip"");             servletOutputStream.flush();         }     }      public static void httpDownloadCompressFileOld(String sourceFilePath, HttpServletResponse response, String zipName) throws IOException {         try (ServletOutputStream servletOutputStream = response.getOutputStream()){             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();             byte[] zipBytes = byteArrayOutputStream.toByteArray();             response.setContentType("application/zip");             response.setHeader("Content-Disposition", "attachment; filename="" + zipName + ".zip"");             response.setContentLength(zipBytes.length);             servletOutputStream.write(zipBytes);             servletOutputStream.flush();         }     }      /**      * 通过网络请求下载zip      *      * @param sourceFilePath       需要压缩的文件路径      * @param response            HttpServletResponse      * @throws IOException      */     public static void httpDownloadCompressFile(String sourceFilePath, HttpServletResponse response) throws IOException {         httpDownloadCompressFile(sourceFilePath, response, null);     }       /**      * 检查文件名是否已经存在,如果存在,就在文件名后面加上“(1)”,如果文件名“(1)”也存在,则改为“(2)”,以此类推。如果文件名不存在,就直接创建一个新文件。      *      * @param filename 文件名      * @return File      */     public static File createNewFile(String filename) {         File file = new File(filename);         if (!file.exists()) {             try {                 file.createNewFile();             } catch (IOException e) {                 e.printStackTrace();             }         } else {             String base = filename.substring(0, filename.lastIndexOf("."));             String ext = filename.substring(filename.lastIndexOf("."));             int i = 1;             while (true) {                 String newFilename = base + "(" + i + ")" + ext;                 file = new File(newFilename);                 if (!file.exists()) {                     try {                         file.createNewFile();                     } catch (IOException e) {                         e.printStackTrace();                     }                     break;                 }                 i++;             }         }         return file;     } } 

FileInfo类代码:

/**  * @author fhey  * @date 2023-05-11 21:01:26  * @description: TODO  */ @Data public class FileInfo {     private InputStream fileInputStream;      private String suffix;      private String fileName;          private boolean isDirectory; } 

测试压缩并在本地生成文件:

public static void main(String[] args) throws Exception {         //在本地创建压缩文件         CompressUtil.createLocalCompressFile("D:\书籍\电子书\医书", "D:\test");     } 

压缩并在本地生成文件验证结果:
Java实现打包压缩文件或文件夹生成zip以实现多文件批量下载

压缩文件并通过http请求下载:

/**  * @author fhey  */ @RestController public class TestController {      @GetMapping(value = "/testFileToZip")     public void testFileToZip(HttpServletResponse response) throws IOException {         String zipFileName = "myFiles";         String sourceFilePath = "D:\picture";         CompressUtil.httpDownloadCompressFile(sourceFilePath,response, zipFileName);     } } 

压缩文件并通过http请求下载验证结果:
Java实现打包压缩文件或文件夹生成zip以实现多文件批量下载