0%

关于同时支持csv和excel大数据量数据导入

前言

最近工作中遇到需要同时支持excel和csv文件导入数据需求,而且数据量最大可达到40w条。

2020.09.18更新

发现通过easyexcel导出生成excel文件,再次通过easyexcel读取时无法得到excel的总行数,解决方法请参照

使用easyexcel读取easyexcel生成的excel文件,无法获取总行数

1
2
3
4
5
6
7
8
9
10
11
12
ExcelWriter excelWriter =EasyExcel.write(out).registerWriteHandler(new AbstractWorkbookWriteHandler() {
@Override
public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {
super.afterWorkbookDispose(writeWorkbookHolder);
Sheet sheet = writeWorkbookHolder.getWorkbook().getSheetAt(0);
if(sheet instanceof SXSSFSheet){
SXSSFSheet sh = ((SXSSFSheet) sheet);
XSSFSheet _sh = (XSSFSheet) ReflectUtil.getFieldValue(sh,"_sh");
_sh.getCTWorksheet().getDimension().setRef("A1:" + CellReference.convertNumToColString(atomicMaxColSize.get()) + atomicRowSize.get());
}
}
}).build();

SXSSFSheet只是XSSFSheet的封装类,内部还是通过XSSFSheet对象操作excel,但并没有提供get方法获取_sh属性,因此通过反射获取即可。

很奇怪,这种问题竟然一直没有解决,看来easyexcel命不久矣。

遇到的问题以及选择

数据量问题

  • csv

    csv方面,由于项目中引用了hutool工具,加上作者本身也是参考fastcsv编写,能很好的支持读取大数据量的csv文件。

    如果你项目没有引用hutool工具,使用fastcsv即可。

  • excel

    在java中处理excel文件最常用的当然非poi莫属了,但poi并没有很好的解决大数据量oom问题,而且poi提供的api较为基础,需要自行封装,无法开箱即用。

    因此我选择基于poi封装的easyexcel操作excel文件。

同时支持csv和excel问题

  • 为csv和excel分别写一套解析代码

    这样很繁琐,需要编写两套代码,如数据校验、数据转换。

  • 将csv转换excel文件

    只需针对excel文件处理即可

解决问题 csv转换为excel

​ 那么现在需要解决的问题就是如何将csv转换为excel文件,本着不重复造轮子的原则,我搜遍了互联网,没有找到能直接用的代码。

索性自己撸一个,借助easyexcel和hutool(fastcsv)工具,写转换代码非常容易,感谢开源社区!

在本机测试下,60w数据转换需要约1分钟。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvRowHandler;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.util.CharsetUtil;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.google.common.collect.Lists;
import com.spepc.railwaypension.common.utils.Clock;
import lombok.extern.slf4j.Slf4j;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
* @author yang
* @date 2020-09-13 10:40
* @des
* @email [email protected]
*/
@Slf4j
public class CvsToExcelUtil {
private CvsToExcelUtil() {
}

/**
*
* @param src csv文件
* @param des excel文件
* @throws Exception
*/
public static void convert(String src, String des) throws Exception {
//计时器
Clock clock = new Clock().start();
CsvReader reader = CsvUtil.getReader();
int batchSize = 1000;
OutputStream out = null;
ExcelWriter excelWriter = null;
AtomicInteger atomicInteger = new AtomicInteger();
//从文件中读取CSV数据
try {
//初始化excel
out = new FileOutputStream(des);
excelWriter = new ExcelWriter(out, ExcelTypeEnum.XLSX, false);
Sheet sheet1 = new Sheet(1, 0);
sheet1.setSheetName("sheet1");
//防止重复扩容
List<List<String>> dataList = Lists.newArrayListWithCapacity(batchSize);
ExcelWriter finalExcelWriter = excelWriter;
reader.read(FileUtil.getReader(src, CharsetUtil.CHARSET_GBK), new CsvRowHandler() {
@Override
public void handle(CsvRow csvRow) {
dataList.add(Arrays.asList(csvRow.toArray(new String[csvRow.size()])));
//释放内存
if(dataList.size()>=batchSize){
finalExcelWriter.write0(dataList, sheet1);
dataList.clear();
atomicInteger.set(atomicInteger.get()+batchSize);
}
}
});
atomicInteger.set(atomicInteger.get()+dataList.size());
excelWriter.write0(dataList, sheet1);
out.flush();
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
if(excelWriter!=null){
excelWriter.finish();
}
IoUtil.close(out);
}
log.info("读取并转换数据:{}条",atomicInteger.get());
log.info("转换总耗时{}秒", clock.stop().getSeconds());
}


public static void main(String[] args) throws Exception {
//测试
convert("F:/test.csv","F:/test.xlsx");
}
}

至此结束,压力山大!

坚持原创技术分享,您的支持将鼓励我继续创作!
YANG 微信支付

微信支付

YANG 支付宝

支付宝