java导出动态表头的CSV文件

CSV相较于xlsx在导出大数据量+字段多的场景下速度更快!

本地测试导出30万条数据,CSV比xlsx快20秒+。不过当数据量小或字段少(2个字段)这种情况下使用CSV并没有明显的优势,并且由于CSV存储相同数据占用的磁盘大小比xlsx的大得多(差不多一倍),在网络传输较为频繁的场景也不适合使用CSV。

以下为动态导出CSV的功能代码,表头不固定。

pom

            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-csv</artifactId>
                <version>1.5</version>
            </dependency>
        

code

/**
     * @param fieldHeaderMap 表头 LinkedHashMap类型,保障表头顺序
     * @param response
     */
public void exportCSV(Map<String,String> fieldHeaderMap, HttpServletResponse response) {
        log.info("开始导出Excel");
        String fileName = "XXX.csv";

        OutputStream outputStream = null;
        CSVPrinter csvPrinter = null;
        OutputStreamWriter osw = null;
        int currentCount = 0;
        try {
            response.reset();
         //虽然是CSV文件,但是可以使用Excel打开,一般也是使用Excel打开,因此设置内容格式为Excel
            response.setHeader("Content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));

            outputStream = response.getOutputStream();
            osw = new OutputStreamWriter(outputStream, "utf-8");

            //解决第一行以ID开头文件打开有报错问题
            osw.write(new String(new byte[] { (byte) 0xEF, (byte) 0xBB,(byte) 0xBF }));

            String[] headerArr = new String[fieldHeaderMap.size()];
            String[] keyArr = new String[fieldHeaderMap.size()];
            fieldHeaderMap.keySet().toArray(keyArr);//字段名称
            fieldHeaderMap.values().toArray(headerArr);//字段中文名称

            //写入表头
            CSVFormat csvFormat = CSVFormat.EXCEL.withHeader(headerArr);
            csvPrinter = new CSVPrinter(osw, csvFormat);

            。。。省略业务判断代码

            Map<String,Object> temp = new LinkedHashMap<>();
            //可设置最大导出条数

            while (currentCount < TaskParam.MAX_DETAIL_LIMIT && currentPage <= totalPage){
                
                List<Map<String, Object>> records = 。。。分页查询数据
                if(CollectionUtils.isEmpty(records)){
                    break;
                }
                currentCount += records.size();

                //需要保证输出的表头与数据对应

                for (Map<String, Object> record : records) {
                    for (String s : keyArr) {
                        temp.put(s, record.get(s));
                    }
                    csvPrinter.printRecord(temp.values());
                    temp.clear();
                }
                csvPrinter.flush();

               //还可以设置超时时间
            }

        } catch (Exception e) {
            log.error("export error ", e);
        } finally {
            if(csvPrinter != null){
                try {
                    csvPrinter.close();
                } catch (IOException e) {
                    log.error("关闭csvPrinter异常", e);
                }
            }
            if(osw != null){
                try {
                    osw.close();
                } catch (IOException e) {
                    log.error("关闭OutputStreamWriter异常", e);
                }
            }
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("关闭outputStream异常", e);
                }
            }
        }
        log.info("写入{}条数据", currentCount);
    }

其中CSV导出的代码没多少,关键的就初始化一个printer,然后调用printRecord将数据写入。

需要注意这句:

osw.write(new String(new byte[] { (byte) 0xEF, (byte) 0xBB,(byte) 0xBF }));

如果不加这句,若第一行数据以ID开头(很多表的主键是叫ID,导出的数据的表头也就是以ID开头了),则导出的CSV打开会报错。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值