POI 分批读取Excel数据

我们在读取excel过程中,通常使用的方案为POI的普通读取,但是遇到大数据量excel (比如一个excel超过20M,上10万行上百列等),此时一般代码会报内存溢出(OOM);


以下为一种解决方案(亲测有效):


首先引入的依赖:


 

       

            org.apache.poi

            poi

            4.0.0

       

 

       

            org.apache.poi

            poi-scratchpad

            4.0.0

       

 

       

       

            com.monitorjbl

            xlsx-streamer

            2.1.0

       

       

            org.apache.poi

            poi-ooxml

            4.0.0

       

       

Java代码:


  /**

     * 大批量数据读取 15W以上

     * 思路:采用分段缓存,防止出现OOM的情况

     * 格式限制:必须使用xlsx的格式,调用前需判断格式

     */

    public static List> readBigExcel(MultipartFile file,String rowname,int stasheetNum,int starowNum,int stacolumn)throws Exception{

        //定义返回值

        List> resultList=new ArrayList>();

        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 paramMap = new HashMap();//定义一个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>  将读取的内容 封装为到一个list中,并以map形式存放;


可根据实际情况进行调整:


注:POI版本需4以上,excel只能读取xlsx格式;

请使用浏览器的分享功能分享到微信等