批量读取zip 压缩文件中的csv格式excel文件

对接在线支付,部分平台的在线支付账单是直接一个zip文件包含着若干csv格式的excel文件,这部分如果想对账什么的还需要把数据提取出来储存到数据库,这里不涉及在线下载,直接用一个本地下载好的支付宝zip账单文件做调试。

zip文件:

 使用postman调用接口:

{
	"filePath": "C:\\Users\\gbx\\Desktop\\20886216051739200156_20230522.csv.zip"
}

因为解读的是csv文件,这里使用EasyExcel作为工具:

        <!-- 解读excel文件 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
        </dependency>

设置读取excel必需的监听类(该监听类技术参考来源:Easy Excel读取复杂表格文件_easyexcel读取复杂excel_MMO_的博客-CSDN博客):

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * EasyExcel监听类
 *
 * @author gbx
 */
@Slf4j
public class EasyExcelListener extends AnalysisEventListener<Object> {
    /**
     * 创建list集合封装最终的数据
     */
    private List<Object> list = new ArrayList<>();
    /**
     * sheet页索引
     */
    private int sheetNo = 0;

    /**
     * 具体读取方法(每一行执行一次)
     *
     * @param t       读取的每一行美容
     * @param context
     */
    @Override
    public void invoke(Object t, AnalysisContext context) {
        //读取内容
        int currentSheetNo = context.readSheetHolder().getSheetNo();
        if (currentSheetNo != sheetNo) {
            // 如果不根据sheet页索引更新状态重新创建list,list会反复添加前面的sheet页对象值
            list = new ArrayList<>();
            sheetNo = currentSheetNo;
        }
        list.add(t);
    }

    /**
     * 开始读取时执行的方法,用以获取表头信息
     *
     * @param headMap 存放表头信息
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        if (ObjectUtils.isNotEmpty(headMap)) {
            list.add(headMap);
        }
    }

    /**
     * 读取完毕后执行方法
     *
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("___读取已完成...___");
    }

    /**
     * 获取表格内容(简单excel读取可用该方法)
     *
     * @param obj 需要转化的实体
     * @param <T>
     * @return
     */
    public <T> List<T> getList(Class<T> obj) {
        JSONArray jsonArray = new JSONArray(list);
        return JSONUtil.toList(jsonArray, obj);
    }

    /**
     * 将表格转化为map集合(复杂excel读取用此方法)
     *
     * @return map集合
     */
    public List<LinkedHashMap> getListMap() {
        JSONArray jsonArray = new JSONArray(list);
        return JSONUtil.toList(jsonArray, LinkedHashMap.class);
    }
}

然后是读取的工具类:

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson2.JSONObject;
import com.gbx.pay.service.monolith.common.utils.file.ZipFileReadUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * excel文件读取工具类
 *
 * @author gbx
 */
@Slf4j
public class EasyExcelReadUtil {

    /**
     * 存储方法(此处只进行打印模拟)
     *
     * @param sheetInfos 数据集合
     */
    private void saveExcelSheetInfos(Map<Integer, List<LinkedHashMap>> sheetInfos) {
        if (sheetInfos == null || sheetInfos.size() <= 0) {
            throw new RuntimeException("excel文件内容为空");
        }

        for (Integer sheetNum : sheetInfos.keySet()) {
            log.info("第" + (sheetNum + 1) + "页内容=======================》START");
            List<LinkedHashMap> contentMapList = sheetInfos.get(sheetNum);
            if (contentMapList != null && contentMapList.size() > 0) {

                for (int i = 0; i < contentMapList.size(); i++) {
                    LinkedHashMap map = contentMapList.get(i);
                    byte[] bytes = StrUtil.bytes(JSONObject.toJSONString(map), "gbk");
                    String str = StrUtil.str(bytes, "gbk");
                    log.info("第" + i + "行内容:" + str);
                }
            }
            log.info("第" + (sheetNum + 1) + "页内容《=======================END");
        }
    }

    /**
     * 解读zip文件
     *
     * @param filePath 文件路径
     */
    public void readZip(String filePath) {
        try {
            List<InputStream> inputStreamList = ZipFileReadUtils.readZipToInputStreamList(filePath, ".csv");
            if (inputStreamList.size() > 0) {
                for (InputStream inputStream : inputStreamList) {
                    // step1. 读取excel内容
                    EasyExcelListener easyExcelListener = new EasyExcelListener();
                    ExcelReaderBuilder read = EasyExcelFactory.read(inputStream, easyExcelListener).charset(Charset.forName("gbk")).excelType(ExcelTypeEnum.CSV);
                    ExcelReader excelReader = read.build();
                    // step2. 获取各个sheet页信息
                    List<ReadSheet> sheets = excelReader.excelExecutor().sheetList();
                    // step3. 获取各个Sheet页表格内容存于map
                    Map<Integer, List<LinkedHashMap>> sheetInfos = new HashMap<>(sheets.size());
                    for (ReadSheet sheet : sheets) {
                        Integer sheetNo = sheet.getSheetNo();
                        excelReader.read(sheet);
                        sheetInfos.put(sheetNo, easyExcelListener.getListMap());
                    }
                    //保存读取出来的数据
                    saveExcelSheetInfos(sheetInfos);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}

此处没有真正执行保存操作,只进行了字符串的展示打印,具体操作按照自己的业务进行下一步操作即可。

展示图:

 

工具类引用了我前篇博文的一个工具类:

import cn.hutool.core.io.FileUtil;
import com.gbx.pay.service.monolith.common.exception.ui.ErrorException;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * zip文件读取工具类
 *
 * @author gbx
 */
public class ZipFileReadUtils {

    /**
     * 解读zip文件
     *
     * @param zipFile    压缩文件
     * @param suffixType 文件后缀(非空时只处理固定后缀的文件)
     * @return 处理结果
     * @throws IOException
     */
    public static List<InputStream> readZipToInputStreamList(File zipFile, String suffixType) throws IOException {
        List<InputStream> list = new ArrayList<>();
        //判断文件是否存在
        if (!zipFile.exists()) {
            throw new ErrorException("无效的zip文件");
        }
        //获取文件流
        InputStream inputStream = FileUtil.getInputStream(zipFile);
        //转化文件流为压缩文件流
        ZipInputStream zipInputStream = new ZipInputStream(inputStream, Charset.forName("gbk"));
        ZipEntry zipEntry;
        while ((zipEntry = zipInputStream.getNextEntry()) != null) {
            //如果文件后缀条件不为空且后缀条件不符则跳过文件读取
            if (StringUtils.isNotBlank(suffixType) && !zipEntry.getName().endsWith(suffixType)) {
                continue;
            }

            //文件读取处理
            byte[] buffer = new byte[1024];
            int len;
            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
            while ((len = zipInputStream.read(buffer)) != -1) {
                byteStream.write(buffer, 0, len);
            }
            // 关闭流
            byteStream.close();

            //读取的文件转为所需的流添加到集合中
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteStream.toByteArray());
            list.add(byteArrayInputStream);
        }
        return list;
    }

    /**
     * 解读zip文件
     *
     * @param filePath   压缩文件路径
     * @param suffixType 文件后缀(非空时只处理固定后缀的文件)
     * @return 处理结果
     * @throws IOException
     */
    public static List<InputStream> readZipToInputStreamList(String filePath, String suffixType) throws IOException {
        File zipFile = new File(filePath);
        return readZipToInputStreamList(zipFile, suffixType);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值