Java Excel文件解析处理,根据条件存入不同文件夹中,打成压缩包(zip)下载

一、最终结果

二、导入pom.xm相关依赖

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.12</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

三、FileUtil工具类

package com.yf.client.util.zipFileUtil;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.yf.utils.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件下载压缩工具类(zip)
 *
 * @author FengQing
 * @program fengqing
 * @description
 * @date 2024/04/25
 */
public class FileUtil {

    // .zip文件名称
    private static final String ZIP_FILE_NAME = "output.zip";

    private static String URL;

    /**
     * 创建文件夹并复制文件
     * @param sourceFilePath 源文件路径
     * @param mkDirName 文件夹名称
     * @param existingFolders 临时文件存储列表
     * @throws IOException
     *
     * 创建虚拟文件对象 路径:/javaProc/oss/广州新居网家居科技有限公司_A0153_32802_20240429154040A006.xlsx
     */
    public static File copyFile(String sourceFilePath, String mkDirName, List<String> existingFolders) throws IOException {
        // 创建文件夹
        String url = StringUtils.substringBeforeLast(sourceFilePath, "\\") + "\\";     //开发本地使用“\\”
        //String url = StringUtils.substringBeforeLast(sourceFilePath, "/") + "/"; // 生产环境使用“/”
        URL = url;
        String folderPath = createMkDirs(url + mkDirName, existingFolders);
        File sourceFile = new File(sourceFilePath);
        File destFile = new File(folderPath + File.separator + sourceFile.getName());
        Files.copy(sourceFile.toPath(), destFile.toPath());
        return destFile;
    }

    /**
     * 创建文件夹
     * @param mkDirName 文件夹名称
     * @param existingFolders 件夹列表暂存区
     * @return 创建的文件夹路径
     */
    public static String createMkDirs(String mkDirName, List<String> existingFolders){
        String folderPath = mkDirName; // 新文件夹路径
        existingFolders.add(mkDirName);
        File folder = new File(mkDirName);
        if (!folder.exists()) {
            folder.mkdirs(); // 创建文件夹
        }
        return folderPath;
    }

    /**
     * 压缩文件列表为ZIP文件并下载
     * @param toBeZippedFiles 文件列表
     * @param response HttpServletResponse对象
     * @throws Exception
     */
    public static void zipFiles(List<File> toBeZippedFiles, HttpServletResponse response) throws Exception {
        byte[] buffer = new byte[1024];
        try (FileOutputStream fos = new FileOutputStream(URL + ZIP_FILE_NAME);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            for (File file : toBeZippedFiles) {
                try (FileInputStream fis = new FileInputStream(file)) {
                    // 获取相对路径,保留文件夹结构
                    String relativePath = getRelativePath(file);
                    ZipEntry ze = new ZipEntry(relativePath);
                    zos.putNextEntry(ze);
                    int len;
                    while ((len = fis.read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }
                    zos.closeEntry();
                }
            }
        }
        getOutputStream(buffer, response);
    }

    /**
     * 将ZIP文件写入HttpServletResponse输出流进行下载
     * @param buffer 缓冲区
     * @param response HttpServletResponse对象
     * @throws Exception
     */
    private static void getOutputStream(byte[] buffer, HttpServletResponse response) throws Exception {
        try (FileInputStream fis = new FileInputStream(URL + ZIP_FILE_NAME);
             BufferedInputStream bis = new BufferedInputStream(fis);
             OutputStream os = response.getOutputStream()) {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + "output.zip");
            int len;
            while ((len = bis.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            os.flush();
        }
    }

    /**
     * 删除临时文件和文件夹(可选)
     * @param existingFolders 临时文件夹路径列表
     */
    public static void deleteMkdirs(List<String> existingFolders){
        if (CollectionUtil.isNotEmpty(existingFolders)) {
            for (String folderPath : existingFolders) {
                File folder = new File(folderPath);
                File[] files = folder.listFiles();
                if (files != null) {
                    for (File file : files) {
                        file.delete();
                    }
                }
                folder.delete();
            }
        }
    }

    /**
     * 删除临时文件和文件夹(可选)
     * @param files 临时文件夹路径列表
     */
    public static void deleteTempFiles(List<File> files) {
        for (File file : files) {
            if (!file.delete()) {
                // 删除失败,输出错误信息
                System.err.println("Failed to delete temp file: " + file.getAbsolutePath());
            }
        }
    }

    /**
     * 获取相对路径,保留文件夹结构
     * @param file 文件
     * @return 相对路径
     */
    public static String getRelativePath(File file) {
        String basePath = URL; // 基础路径
        String filePath = file.getAbsolutePath();
        if (filePath.startsWith(basePath)) {
            // 返回去除基础路径后的相对路径
            return filePath.substring(basePath.length());
        } else {
            // 如果路径不在基础路径下,直接返回文件名
            return file.getName();
        }
    }

    /**
     * 截取“去除桶名称”,保留相对路径
     * @param url
     * @return
     */
    public static String extractFilePath(String url) {
        int rootIndex = url.indexOf("/", 1); // 从第二个字符开始查找斜杠
        return rootIndex != -1 ? url.substring(rootIndex + 1) : null;
    }

    /**
     * 读取文件流解析到文件名称集
     * @param file
     * @return
     * @throws IOException
     */
    public static List<String> getEasyExcelFileNames(MultipartFile file) throws IOException {
        EasyExcelUtil listener = new EasyExcelUtil();
        EasyExcel.read(file.getInputStream(), listener).sheet().doRead();
        List<Map<Integer, String>> targetColumnData = listener.getTargetColumnData();
        return targetColumnData.stream()
                .map(v -> v.get(0))
                .distinct()
                .collect(Collectors.toList());
    }
}

四、业务层impl处理

/**
     * 文件筛查(自动下载)接口(Excel文件解析处理)
     * @return
     * @throws Exception
     */
    @Override
    public void downloadFileScreen(MultipartFile file, HttpServletResponse response) throws Exception {
        log.info("文件名称集file:{}", file.getOriginalFilename());
        // 这里 只要,然后读取第一个sheet 同步读取会自动finish
        //List<String> easyExcelFileNames = FileUtil.getEasyExcelFileNames(file);

        // 1、上传文件名称:根据文件名称查询数据库中文件 URL 地址
        /*List<String> urlList = this.selectFileScreenList(easyExcelFileNames);
        if (StringUtils.isNull(urlList) || urlList.size() == 0) {
            throw new RuntimeException("系统中未查询到文件地址信息!");
        }*/
       // log.info("数据库查询url地址集:{}", urlList);
        List<String> urlList = new ArrayList<>();
        String fileName = "/file-screen-bucket/2024/04/30/xxxx02有限公司_A34947_32769_20240430082633A005.xlsx"; // Excel文件路径
        String fileName1 = "/file-screen-bucket/2024/04/30/xxxxxx01有限公司_A34946_6_20240430082624A004.xlsx"; // Excel文件路径
        urlList.add(fileName);
        urlList.add(fileName1);

        // 2、遍历文件,解析Excel数据进行判断,存入不同文件夹中或输出.zip文件
        List<String> existingFolders = new ArrayList<>();
        List<java.io.File> toBeZippedFiles = new ArrayList<>();
        List<java.io.File> tempFiles = new ArrayList<>(); // 存储临时文件
        for (String url : urlList) {
            //截取“去除桶名称”,保留相对路径
            String extractedPath = FileUtil.extractFilePath(url);
            if (extractedPath != null) {
                // 根据相对路径读取minio文件流
                byte[] bytes = localSysFileFeignService.getExtractedPath(extractedPath);

                // 创建临时文件(截取原文件名称)
                java.io.File tempFile = new java.io.File(StringUtils.substringAfterLast(extractedPath, "/"));
                tempFiles.add(tempFile);
                try (InputStream inputStream = new ByteArrayInputStream(bytes);
                     FileOutputStream outputStream = new FileOutputStream(tempFile)) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                }
                // 创建虚拟文件对象
                String absolutePath = tempFile.getAbsolutePath();
                log.info("创建虚拟文件对象 路径:{}", absolutePath);
                EasyExcelUtil listener = new EasyExcelUtil();
                EasyExcel.read(absolutePath, listener).sheet().doRead();
                List<Map<Integer, String>> targetColumnData = listener.getTargetColumnData();
                List<String> addList = targetColumnData.stream()
                        .map(v -> v.get(1))
                        .distinct()
                        .collect(Collectors.toList());
                log.info("去重后的数量:{}", addList.size());

                // 符合条件存入不同文件夹中
                if (addList.size() < 20) {
                    java.io.File destFile = FileUtil.copyFile(absolutePath, "小于20", existingFolders);
                    // 复制的文件添加到待压缩文件列表将表
                    toBeZippedFiles.add(destFile); // 将复制的文件添加到待压缩文件列表
                } else if (addList.size() > 20) {
                    java.io.File destFile = FileUtil.copyFile(absolutePath, "大于20", existingFolders);
                    toBeZippedFiles.add(destFile); // 将复制的文件添加到待压缩文件列表
                } else {
                    toBeZippedFiles.add(new java.io.File(absolutePath)); // 不符合条件的文件直接添加到待压缩文件列表
                }
            } else {
                // 处理文件路径不合法的情况
                System.out.println("文件路径不合法");
            }
        }
        log.info("tempFiles临时文件 路径:{}", tempFiles);
        log.info("toBeZippedFiles列表 路径:{}", toBeZippedFiles);
        log.info("existingFolders列表 路径:{}", existingFolders);
        // 3、将待压缩的文件打包成zip并添加到输出.zip文件
        FileUtil.zipFiles(toBeZippedFiles, response);
        // 4、删除临时文件和文件夹(可选)
        FileUtil.deleteMkdirs(existingFolders);
        // 5、删除(创建临时文件)
        FileUtil.deleteTempFiles(tempFiles);
        FileUtil.deleteTempFiles(toBeZippedFiles);
    }

五、控制层Controller

/**
     * 文件筛查(自动下载)接口(Excel文件解析处理)
     * @return
     */
    @ApiOperation(value = "文件筛查自动下载接口", notes = "文件筛查自动下载接口")
    @PostMapping("/download")
    public void downloadFileScreen(@RequestParam("file") MultipartFile file, HttpServletResponse response) throws Exception {
        iFileScreenService.downloadFileScreen(file, response);
    }

调用示例:

  • 11
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值