POI 分批讀取Excel資料

xz43發表於2022-05-17

我們在讀取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格式;

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9399028/viewspace-2894802/,如需轉載,請註明出處,否則將追究法律責任。

相關文章