每一年都奔走在自己热爱里 没有人是一座孤岛,总有谁爱着你

岁
万
月
12

将多个文件、文件夹压缩成Zip并导出

项目地址:https://gitee.com/libeimaningg/beizhilib


在Spring Boot中将本地多个文件和文件夹压缩成Zip并导出,可以通过以下步骤实现。这里采用流式压缩,避免创建临时文件,适合大文件处理:

一、创建Zip压缩工具类

package org.yaoyao.yaoyaocommon.utils;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StreamUtils;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.nio.file.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Zip工具类
 *
 * @author Bryson
 * @date 2025/4/2
 */
public class ZipUtils {

    public static void compressToZip(HttpServletResponse response, String folderPath,
                                     List<String> filePaths,
                                     String zipName) throws IOException {
        // 设置响应头
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + zipName + "\"");

        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
            for (String path : filePaths) {
                Path filePath = Paths.get(folderPath + "/" + path);
                if (Files.exists(filePath)) {
                    addToZip(filePath, zos, "");
                }
            }
            zos.finish();
        } catch (IOException e) {
            throw new IOException(e.getMessage());
        }
    }

    private static void addToZip(Path source, ZipOutputStream zos, String parentDir) throws IOException {
        String entryName = parentDir + source.getFileName().toString();

        if (Files.isDirectory(source)) {
            // 处理目录:在Zip中创建目录条目,并递归处理子文件
            if (!entryName.endsWith("/")) {
                entryName += "/";
            }
            zos.putNextEntry(new ZipEntry(entryName));
            zos.closeEntry();

            try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(source)) {
                for (Path child : dirStream) {
                    addToZip(child, zos, entryName);
                }
            }
        } else {
            // 处理文件:创建条目并写入数据
            ZipEntry zipEntry = new ZipEntry(entryName);
            zos.putNextEntry(zipEntry);
            Files.copy(source, zos);
            zos.closeEntry();
        }
    }
}

二、创建下载请求

1、Controller层

/**
     * 将多个文件、文件夹压缩成Zip并导出
     * @param response
     * @throws IOException
     */
    @PostMapping("/downloadZip")
    public void downloadZip(HttpServletResponse response) throws IOException {
        fileService.downloadZip(response);
    }

2、实现层

@Override
    public void downloadZip(HttpServletResponse response) throws IOException {
        try {
            if (FileUtil.exist(folderPath)) {
                //获取folderPath路径下的文件名称
                List<String> filePaths = FileUtil.listFileNames(folderPath);
                //使用时间戳命名压缩包文件
                //小记:SimpleDateFormat 是非线程安全的,推荐用 DateTimeFormatte
                //如果必须使用 SimpleDateFormat,应通过 ThreadLocal 实现线程隔离
                String safeTimestamp = LocalDateTime.now()
                        .format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
                // 调用压缩方法并导出
                ZipUtils.compressToZip(response, folderPath, filePaths, safeTimestamp + ".zip");
            } else {
                throw new BusinessException(StatusEnums.FAIL, BusinessEnums.FAIL.getType(), "文件不存在");
            }
        } catch (Exception e) {
            log.info("###############zip文件生成失败###############");
            e.printStackTrace();
        }
    }

folderPath="E:\file"

image
List<\String> filePaths的数据为这些文件的名称。

三、导出结果

image

四、关键点说明

1. 流式压缩

  • 直接使用HttpServletResponse的输出流,避免内存溢出
  • 使用try-with-resources确保资源自动关闭

2. 目录处理

  • 自动识别目录并递归处理子文件
  • 在Zip中创建目录条目(以/结尾)

3. 编码处理

  • 默认使用UTF-8编码文件名
  • 如需处理特殊字符,可添加:
response.setCharacterEncoding("UTF-8");

4. 大文件支持

  • 使用NIO的Files.copy()方法实现高效文件复制
  • 每次只处理一个文件,内存占用恒定
posted @ 2025-04-02 17:59  果咩那塞  阅读(5)  评论(0)    收藏  举报