翼度科技»论坛 编程开发 JavaScript 查看内容

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

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
有时候在系统中需要一次性下载多个文件,但逐个下载文件比较麻烦。这时候,最好的解决办法是将所有文件打包成一个压缩文件,然后下载这个压缩文件,这样就可以一次性获取所有所需的文件了。
下面是一个名为CompressUtil的工具类的代码,它提供了一些方法来处理文件压缩和下载操作:
  1. import org.apache.commons.lang3.ArrayUtils;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.apache.lucene.util.RamUsageEstimator;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import javax.servlet.ServletOutputStream;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.io.*;
  9. import java.util.*;
  10. import java.util.zip.*;
  11. /**
  12. * @author fhey
  13. * @date 2023-05-11 20:48:28
  14. * @description: 压缩工具类
  15. */
  16. public class CompressUtil {
  17.     private static final Logger logger = LoggerFactory.getLogger(CompressUtil.class);
  18.     /**
  19.      * 将文件打包到zip并创建文件
  20.      *
  21.      * @param sourceFilePath
  22.      * @param zipFilePath
  23.      * @throws IOException
  24.      */
  25.     public static void createLocalCompressFile(String sourceFilePath, String zipFilePath) throws IOException {
  26.         createLocalCompressFile(sourceFilePath, zipFilePath, null);
  27.     }
  28.     /**
  29.      * 将文件打包到zip并创建文件
  30.      *
  31.      * @param sourceFilePath
  32.      * @param zipFilePath
  33.      * @param zipName
  34.      * @throws IOException
  35.      */
  36.     public static void createLocalCompressFile(String sourceFilePath, String zipFilePath, String zipName) throws IOException {
  37.         File sourceFile = new File(sourceFilePath);
  38.         if (!sourceFile.exists()) {
  39.             throw new RuntimeException(sourceFilePath + "不存在!");
  40.         }
  41.         if(StringUtils.isBlank(zipName)){
  42.             zipName = sourceFile.getName();
  43.         }
  44.         File zipFile = createNewFile(zipFilePath + File.separator + zipName + ".zip");
  45.         try (FileOutputStream fileOutputStream = new FileOutputStream(zipFile)) {
  46.             compressFile(sourceFile, fileOutputStream);
  47.         }
  48.     }
  49.     /**
  50.      * 获取压缩文件流
  51.      *
  52.      * @param sourceFilePath
  53.      * @return ByteArrayOutputStream
  54.      * @throws IOException
  55.      */
  56.     public static OutputStream compressFile(String sourceFilePath, OutputStream outputStream) throws IOException {
  57.         File sourceFile = new File(sourceFilePath);
  58.         if (!sourceFile.exists()) {
  59.             throw new RuntimeException(sourceFilePath + "不存在!");
  60.         }
  61.         return compressFile(sourceFile, outputStream);
  62.     }
  63.     /**
  64.      * 获取压缩文件流
  65.      *
  66.      * @param sourceFile
  67.      * @return ByteArrayOutputStream
  68.      * @throws IOException
  69.      */
  70.     private static OutputStream compressFile(File sourceFile, OutputStream outputStream) throws IOException {
  71.         try (CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream, new CRC32());
  72.              ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream)) {
  73.             doCompressFile(sourceFile, zipOutputStream, StringUtils.EMPTY);
  74.             return outputStream;
  75.         }
  76.     }
  77.     /**
  78.      * 处理目录下的文件
  79.      *
  80.      * @param sourceFile
  81.      * @param zipOutputStream
  82.      * @param zipFilePath
  83.      * @throws IOException
  84.      */
  85.     private static void doCompressFile(File sourceFile, ZipOutputStream zipOutputStream, String zipFilePath) throws IOException {
  86.         // 如果文件是隐藏的,不进行压缩
  87.         if (sourceFile.isHidden()) {
  88.             return;
  89.         }
  90.         if (sourceFile.isDirectory()) {//如果是文件夹
  91.             handDirectory(sourceFile, zipOutputStream, zipFilePath);
  92.         } else {//如果是文件就添加到压缩包中
  93.             try (FileInputStream fileInputStream = new FileInputStream(sourceFile)) {
  94.                 //String fileName = zipFilePath + File.separator + sourceFile.getName();
  95.                 String fileName = zipFilePath + sourceFile.getName();
  96.                 addCompressFile(fileInputStream, fileName, zipOutputStream);
  97.                 //String fileName = zipFilePath.replace("\", "/") + "/" + sourceFile.getName();
  98.                 //addCompressFile(fileInputStream, fileName, zipOutputStream);
  99.             }
  100.         }
  101.     }
  102.     /**
  103.      * 处理文件夹
  104.      *
  105.      * @param dir         文件夹
  106.      * @param zipOut      压缩包输出流
  107.      * @param zipFilePath 压缩包中的文件夹路径
  108.      * @throws IOException
  109.      */
  110.     private static void handDirectory(File dir, ZipOutputStream zipOut, String zipFilePath) throws IOException {
  111.         File[] files = dir.listFiles();
  112.         if (ArrayUtils.isEmpty(files)) {
  113.             ZipEntry zipEntry = new ZipEntry(zipFilePath + dir.getName() + File.separator);
  114.             zipOut.putNextEntry(zipEntry);
  115.             zipOut.closeEntry();
  116.             return;
  117.         }
  118.         for (File file : files) {
  119.             doCompressFile(file, zipOut, zipFilePath + dir.getName() + File.separator);
  120.         }
  121.     }
  122.     /**
  123.      * 获取压缩文件流
  124.      *
  125.      * @param documentList 需要压缩的文件集合
  126.      * @return ByteArrayOutputStream
  127.      */
  128.     public static OutputStream compressFile(List<FileInfo> documentList, OutputStream outputStream) {
  129.         Map<String, List<FileInfo>> documentMap = new HashMap<>();
  130.         documentMap.put("", documentList);
  131.         return compressFile(documentMap, outputStream);
  132.     }
  133.     /**
  134.      * 将文件打包到zip
  135.      *
  136.      * @param documentMap 需要下载的附件集合 map的key对应zip里的文件夹名
  137.      * @return ByteArrayOutputStream
  138.      */
  139.     public static OutputStream compressFile(Map<String, List<FileInfo>> documentMap, OutputStream outputStream) {
  140.         CheckedOutputStream checkedOutputStream = new CheckedOutputStream(outputStream, new CRC32());
  141.         ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream);
  142.         try {
  143.             for (Map.Entry<String, List<FileInfo>> documentListEntry : documentMap.entrySet()) {
  144.                 String dirName = documentMap.size() > 1 ? documentListEntry.getKey() : "";
  145.                 Map<String, Integer> fileNameToLen = new HashMap<>();//记录单个合同号文件夹下每个文件名称出现的次数(对重复文件名重命名)
  146.                 for (FileInfo document : documentListEntry.getValue()) {
  147.                     try {
  148.                         //防止单个文件夹下文件名重复 对重复的文件进行重命名
  149.                         String documentName = document.getFileName();
  150.                         if (fileNameToLen.get(documentName) == null) {
  151.                             fileNameToLen.put(documentName, 1);
  152.                         } else {
  153.                             int fileLen = fileNameToLen.get(documentName) + 1;
  154.                             fileNameToLen.put(documentName, fileLen);
  155.                             documentName = documentName + "(" + fileLen + ")";
  156.                         }
  157.                         String fileName = documentName + "." + document.getSuffix();
  158.                         if (StringUtils.isNotBlank(dirName)) {
  159.                             fileName = dirName + File.separator + fileName;
  160.                         }
  161.                         addCompressFile(document.getFileInputStream(), fileName, zipOutputStream);
  162.                     } catch (Exception e) {
  163.                         logger.info("filesToZip exception :", e);
  164.                     }
  165.                 }
  166.             }
  167.         } catch (Exception e) {
  168.             logger.error("filesToZip exception:" + e.getMessage(), e);
  169.         }
  170.         return outputStream;
  171.     }
  172.     /**
  173.      * 将单个文件写入文件压缩包
  174.      *
  175.      * @param inputStream     文件输入流
  176.      * @param fileName        文件在压缩包中的相对全路径
  177.      * @param zipOutputStream 压缩包输出流
  178.      */
  179.     private static void addCompressFile(InputStream inputStream, String fileName, ZipOutputStream zipOutputStream) {
  180.         try (BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
  181.             ZipEntry zipEntry = new ZipEntry(fileName);
  182.             zipOutputStream.putNextEntry(zipEntry);
  183.             byte[] bytes = new byte[1024];
  184.             int length;
  185.             while ((length = bufferedInputStream.read(bytes)) >= 0) {
  186.                 zipOutputStream.write(bytes, 0, length);
  187.                 zipOutputStream.flush();
  188.             }
  189.             zipOutputStream.closeEntry();
  190.             //System.out.println("map size, value is " + RamUsageEstimator.sizeOf(zipOutputStream));
  191.         } catch (Exception e) {
  192.             logger.info("addFileToZip exception:", e);
  193.             throw new RuntimeException(e);
  194.         }
  195.     }
  196.     /**
  197.      * 通过网络请求下载zip
  198.      *
  199.      * @param sourceFilePath       需要压缩的文件路径
  200.      * @param response            HttpServletResponse
  201.      * @param zipName            压缩包名称
  202.      * @throws IOException
  203.      */
  204.     public static void httpDownloadCompressFile(String sourceFilePath, HttpServletResponse response, String zipName) throws IOException {
  205.         File sourceFile = new File(sourceFilePath);
  206.         if (!sourceFile.exists()) {
  207.             throw new RuntimeException(sourceFilePath + "不存在!");
  208.         }
  209.         if(StringUtils.isBlank(zipName)){
  210.             zipName = sourceFile.getName();
  211.         }
  212.         try (ServletOutputStream servletOutputStream = response.getOutputStream()){
  213.             CompressUtil.compressFile(sourceFile, servletOutputStream);
  214.             response.setContentType("application/zip");
  215.             response.setHeader("Content-Disposition", "attachment; filename="" + zipName + ".zip"");
  216.             servletOutputStream.flush();
  217.         }
  218.     }
  219.     public static void httpDownloadCompressFileOld(String sourceFilePath, HttpServletResponse response, String zipName) throws IOException {
  220.         try (ServletOutputStream servletOutputStream = response.getOutputStream()){
  221.             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  222.             byte[] zipBytes = byteArrayOutputStream.toByteArray();
  223.             response.setContentType("application/zip");
  224.             response.setHeader("Content-Disposition", "attachment; filename="" + zipName + ".zip"");
  225.             response.setContentLength(zipBytes.length);
  226.             servletOutputStream.write(zipBytes);
  227.             servletOutputStream.flush();
  228.         }
  229.     }
  230.     /**
  231.      * 通过网络请求下载zip
  232.      *
  233.      * @param sourceFilePath       需要压缩的文件路径
  234.      * @param response            HttpServletResponse
  235.      * @throws IOException
  236.      */
  237.     public static void httpDownloadCompressFile(String sourceFilePath, HttpServletResponse response) throws IOException {
  238.         httpDownloadCompressFile(sourceFilePath, response, null);
  239.     }
  240.     /**
  241.      * 检查文件名是否已经存在,如果存在,就在文件名后面加上“(1)”,如果文件名“(1)”也存在,则改为“(2)”,以此类推。如果文件名不存在,就直接创建一个新文件。
  242.      *
  243.      * @param filename 文件名
  244.      * @return File
  245.      */
  246.     public static File createNewFile(String filename) {
  247.         File file = new File(filename);
  248.         if (!file.exists()) {
  249.             try {
  250.                 file.createNewFile();
  251.             } catch (IOException e) {
  252.                 e.printStackTrace();
  253.             }
  254.         } else {
  255.             String base = filename.substring(0, filename.lastIndexOf("."));
  256.             String ext = filename.substring(filename.lastIndexOf("."));
  257.             int i = 1;
  258.             while (true) {
  259.                 String newFilename = base + "(" + i + ")" + ext;
  260.                 file = new File(newFilename);
  261.                 if (!file.exists()) {
  262.                     try {
  263.                         file.createNewFile();
  264.                     } catch (IOException e) {
  265.                         e.printStackTrace();
  266.                     }
  267.                     break;
  268.                 }
  269.                 i++;
  270.             }
  271.         }
  272.         return file;
  273.     }
  274. }
复制代码
FileInfo类代码:
  1. /**
  2. * @author fhey
  3. * @date 2023-05-11 21:01:26
  4. * @description: TODO
  5. */
  6. @Data
  7. public class FileInfo {
  8.     private InputStream fileInputStream;
  9.     private String suffix;
  10.     private String fileName;
  11.    
  12.     private boolean isDirectory;
  13. }
复制代码
测试压缩并在本地生成文件:
  1. public static void main(String[] args) throws Exception {
  2.         //在本地创建压缩文件
  3.         CompressUtil.createLocalCompressFile("D:\\书籍\\电子书\\医书", "D:\\test");
  4.     }
复制代码
压缩并在本地生成文件验证结果:

压缩文件并通过http请求下载:
  1. /**
  2. * @author fhey
  3. */
  4. @RestController
  5. public class TestController {
  6.     @GetMapping(value = "/testFileToZip")
  7.     public void testFileToZip(HttpServletResponse response) throws IOException {
  8.         String zipFileName = "myFiles";
  9.         String sourceFilePath = "D:\\picture";
  10.         CompressUtil.httpDownloadCompressFile(sourceFilePath,response, zipFileName);
  11.     }
  12. }
复制代码
压缩文件并通过http请求下载验证结果:


来源:https://www.cnblogs.com/fhey/p/17433021.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具