天天看點

EasyExcel如何解決臨時檔案過大問題

作者:莊家钜Jerry

在使用EasyExcel導出excel的時候,會遇到占用大量磁盤的問題,當并發比較大時,會使伺服器檔案撐滿。

原因排查

書寫測試代碼

/**
     * 壓縮臨時檔案
     * 在導出Excel且格式為xlsx的時候會生成一個臨時的xml檔案,會比較大,再磁盤不太夠的情況下,可以壓縮。
     * 當然壓縮式耗費性能的
     */
    @Test
    public void compressedTemporaryFile() {
        log.info("臨時的xml存儲在:{}", FileUtils.getPoiFilesPath());
        File file = TestFileUtil.createNewFile("rare/compressedTemporaryFile" + System.currentTimeMillis()
            + ".xlsx");
        // 這裡 需要指定寫用哪個class去寫
        try (ExcelWriter excelWriter = EasyExcel.write(file, DemoData.class).build()) {
            // 這裡注意 如果同一個sheet隻要建立一次
            WriteSheet writeSheet = EasyExcel.writerSheet("模闆").build();
            // 10萬資料 確定有足夠的空間
            for (int i = 0; i < 10000; i++) {
                // 分頁去資料庫查詢資料 這裡可以去資料庫查詢每一頁的資料
                List<DemoData> data = data();
                excelWriter.write(data, writeSheet);
            }
            log.info("寫入完畢,開始準備遷移壓縮檔案。");
        }
    }

    private List<DemoData> data() {
        List<DemoData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字元串" + i);
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }           

檢視臨時目錄的檔案大小

把斷點設定在`log.info("寫入完畢,開始準備遷移壓縮檔案。");` 這一行

可以看到1萬3行的資料,就占用了17M記憶體,當資料量大了時候占用的磁盤會更大。

EasyExcel如何解決臨時檔案過大問題

然後代碼繼續運作完成,會發現這個檔案被删除了。

EasyExcel如何解決臨時檔案過大問題

結論

是以這個檔案占用是臨時的,最後會自動删除。

解決方案

将這個臨時的xml做壓縮處理。配置方法如下:

/**
     * 壓縮臨時檔案
     * 在導出Excel且格式為xlsx的時候會生成一個臨時的xml檔案,會比較大,再磁盤不太夠的情況下,可以壓縮。
     * 當然壓縮式耗費性能的
     */
    @Test
    public void compressedTemporaryFile() {
        log.info("臨時的xml存儲在:{}", FileUtils.getPoiFilesPath());
        File file = TestFileUtil.createNewFile("rare/compressedTemporaryFile" + System.currentTimeMillis()
            + ".xlsx");

        // 這裡 需要指定寫用哪個class去寫
        try (ExcelWriter excelWriter = EasyExcel.write(file, DemoData.class).registerWriteHandler(
            new WorkbookWriteHandler() {

                /**
                 * 攔截Workbook建立完成事件
                 * @param context
                 */
                @Override
                public void afterWorkbookCreate(WorkbookWriteHandlerContext context) {
                    // 擷取到Workbook對象
                    Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();
                    // 隻有SXSSFWorkbook模式才會生成臨時檔案
                    if (workbook instanceof SXSSFWorkbook) {
                        SXSSFWorkbook sxssfWorkbook = (SXSSFWorkbook)workbook;
                        // 設定臨時檔案壓縮,當然這個會浪費cpu性能 但是臨時檔案會變小
                        sxssfWorkbook.setCompressTempFiles(true);
                    }
                }
            }).build()) {
            // 這裡注意 如果同一個sheet隻要建立一次
            WriteSheet writeSheet = EasyExcel.writerSheet("模闆").build();
            // 10萬資料 確定有足夠的空間
            for (int i = 0; i < 10000; i++) {
                // 分頁去資料庫查詢資料 這裡可以去資料庫查詢每一頁的資料
                List<DemoData> data = data();
                excelWriter.write(data, writeSheet);
            }
            log.info("寫入完畢,開始準備遷移壓縮檔案。");
        }
    }           

重新運作

EasyExcel如何解決臨時檔案過大問題

可以看到臨時檔案由17M變成了1.2M。

繼續閱讀