赞
踩
我们在读取excel过程中,通常使用的方案为POI的普通读取,但是遇到大数据量excel (比如一个excel超过20M,上10万行上百列等),此时一般代码会报内存溢出(OOM);
以下为一种解决方案(亲测有效):
首先引入的依赖:
- <!--大批量excel导入依赖开始-->
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi</artifactId>
- <version>4.0.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-scratchpad</artifactId>
- <version>4.0.0</version>
- </dependency>
-
- <!-- 读取大量excel数据时使用 -->
- <dependency>
- <groupId>com.monitorjbl</groupId>
- <artifactId>xlsx-streamer</artifactId>
- <version>2.1.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml</artifactId>
- <version>4.0.0</version>
- </dependency>
- <!--大批量excel导入依赖结束-->
Java代码:
- /**
- * 大批量数据读取 15W以上
- * 思路:采用分段缓存,防止出现OOM的情况
- * 格式限制:必须使用xlsx的格式,调用前需判断格式
- */
- public static List<Map<String,Object>> readBigExcel(MultipartFile file,String rowname,int stasheetNum,int starowNum,int stacolumn)throws Exception{
- //定义返回值
- List<Map<String,Object>> resultList=new ArrayList<Map<String,Object>>();
- InputStream inputStream=file.getInputStream();
- try( Workbook wk= StreamingReader.builder()
- .rowCacheSize(100) //缓存到内存中的行数,默认是10
- .bufferSize(4096) //读取资源时,缓存到内存的字节大小,默认是1024
- .open(inputStream); ){ //打开资源,必须,可以是InputStream或者是File,注意:只能打开XLSX格式的文件
- Sheet sheet = wk.getSheetAt(stasheetNum);
- String[] rownameSplit=rowname.split(",");
- int columnlength=rownameSplit.length;
- Cell cell=null;//定义单元格
- //遍历所有的行()
- for (Row row :sheet) {
- //row=sheet.getRow(i);//获取当前循环的行数据(因为只缓存了部分数据,所以不能用getRow来获取)此处采用增强for循环直接获取row对象
- Map<String, Object> paramMap = new HashMap<String, Object>();//定义一个map做数据接收
- if (row.getRowNum() >= starowNum) { //从设定的行开始取值
- //System.out.println("开始遍历第" + row.getRowNum() + "行数据:");
- //对当前行逐列进行循环取值
- for (int j = stacolumn; j < columnlength; j++) {
- /**
- 注:MyUtil.isEmpty为工具类判空方法,可替换为自己的判空工具
- **/
- if (MyUtil.isEmpty(row)) {
- paramMap.put(rownameSplit[j], null);//将单元格值放入map
- } else {
- cell = row.getCell(j);//获取单元格数据
- if (MyUtil.isEmpty(cell) && cell.getCellType() == CellType.BLANK) {
- paramMap.put(rownameSplit[j], null);//将单元格值放入map
- } else {
- paramMap.put(rownameSplit[j], cell.getStringCellValue());//将单元格值放入map
- }
-
- }
-
- }
- //一行循环完成,将map存入list
- resultList.add(paramMap);
- }
- }
-
-
- }
- return resultList;
- }
参数解释:
file:前台页面传递的文件
rowname:为读取的每个列起的名字。如excel文件列为 姓名,身份证,性别 ;此处可传字符串"name,card,sex";
stasheetNum:读取的工作簿 从0开始
starowNum: 开始读取的行 从0开始
stacolumn:开始读取的列 从0开始
返回值:List<Map<String,Object>> 将读取的内容 封装为到一个list中,并以map形式存放;
可根据实际情况进行调整:
注:POI版本需4以上,excel只能读取xlsx格式;如有更好方案 欢迎留言分享
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。