java导出动态表头的CSV文件

本文对比了CSV和XLSX在大数据量及多字段情况下的导出效率,指出CSV导出速度更快,但在小数据量或字段少的情况下优势不明显。同时,文章详细介绍了使用Apache Commons CSV库动态导出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打开会报错。

 

 

### Java导出 CSV 文件并使表头文字加粗 CSV 文件本质上是一个纯文本文件,通常用于存储表格数据。由于 CSV 文件不支持样式(如字体加粗),因此无法直接通过标准的 CSV 格式来表示加粗的文字[^1]。 然而,在某些情况下,可以采用变通的方法来模拟这种效果: #### 使用特殊标记符 可以在 CSV 文件中加入特殊的标记符,比如在表头前后加上特定字符 `*` 或者 `_` 来指示这是需要特别显示的部分。但这依赖于读取该 CSV 文件的应用程序能够识别这些标记,并相应调整其渲染方式。 ```java // 假设有一个简单的列表作为要导出的数据 List<String[]> data = Arrays.asList( new String[]{"*姓名*", "*年龄*", "*性别*"}, // 表头部分使用 * 包围以示区分 new String[]{"张三", "28", "男"}, new String[]{"李四", "30", "女"} ); ``` #### 转换为 Excel (.xlsx) 文件 更推荐的做法是创建一个 `.xlsx` 文件而不是普通的 CSV 文件。这样不仅可以保存复杂的格式信息(包括但不限于字体颜色、大小、边框以及单元格背景色等),还可以利用 Apache POI 库轻松完成这一操作[^3]。 下面给出一段简单代码片段展示如何用 POI 创建带格式化的 Excel 工作簿并将之下载给客户端: ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.streaming.SXSSFWorkbook; ... Workbook workbook = new SXSSFWorkbook(); Sheet sheet = workbook.createSheet("sheetName"); Row headerRow = sheet.createRow(0); CellStyle style = workbook.createCellStyle(); Font font = workbook.createFont(); font.setBold(true); // 设置字体为粗体 style.setFont(font); for (int i = 0; i < headers.length; ++i){ Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(style); } // 继续填充其他行... ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值