在使用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記憶體,當資料量大了時候占用的磁盤會更大。
然後代碼繼續運作完成,會發現這個檔案被删除了。
結論
是以這個檔案占用是臨時的,最後會自動删除。
解決方案
将這個臨時的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("寫入完畢,開始準備遷移壓縮檔案。");
}
}
重新運作
可以看到臨時檔案由17M變成了1.2M。