Java EasyExcel導出報內存溢出的解決辦法
EasyExcel大數(shù)據(jù)量導出常見方法
1. 分批寫入
- EasyExcel支持分批寫入數(shù)據(jù),可以將數(shù)據(jù)分批加載到內存中,分批寫入Excel文件,避免一次性將大量數(shù)據(jù)加載到內存中。
- 示例代碼:
String fileName = "large_data.xlsx"; ExcelWriter excelWriter = EasyExcel.write(fileName).build(); WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); // 假設每次寫入10000條數(shù)據(jù) int batchSize = 10000; List<Data> dataList; int pageIndex = 0; do { // 分頁獲取數(shù)據(jù) dataList = getDataByPage(pageIndex++, batchSize); excelWriter.write(dataList, writeSheet); } while (dataList.size() == batchSize); // 關閉資源 excelWriter.finish();
2. 設置合適的JVM內存
- 針對大數(shù)據(jù)導出場景,可以嘗試增大JVM的內存分配,例如:
java -Xms512M -Xmx4G -jar yourApp.jar
- 解釋:
-Xms512M
:設置初始堆大小為512MB。-Xmx4G
:設置最大堆大小為4GB。
3. 減少數(shù)據(jù)對象的復雜性
- 導出數(shù)據(jù)時,盡量簡化數(shù)據(jù)對象,避免不必要的嵌套和多余字段的加載,以減少對象占用的內存空間。
4. 關閉自動列寬設置
- EasyExcel的自動列寬功能會占用大量內存,特別是在數(shù)據(jù)量較大的情況下。關閉自動列寬可以節(jié)省內存。
- 示例代碼:
EasyExcel.write(fileName) .registerWriteHandler(new SimpleWriteHandler()) // 不使用自動列寬 .sheet("Sheet1") .doWrite(dataList);
5. 使用Stream導出(適合大數(shù)據(jù))
- 利用
OutputStream
分批寫入數(shù)據(jù),減少內存消耗。通過BufferedOutputStream
可以進一步提高性能。 - 示例代碼:
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(fileName))) { ExcelWriter excelWriter = EasyExcel.write(out).build(); WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); int pageIndex = 0; List<Data> dataList; do { dataList = getDataByPage(pageIndex++, batchSize); excelWriter.write(dataList, writeSheet); } while (dataList.size() == batchSize); excelWriter.finish(); } catch (IOException e) { e.printStackTrace(); }
6. 選擇合適的數(shù)據(jù)導出工具
- 如果數(shù)據(jù)量非常大,可以考慮切換到支持更高性能的導出工具(如Apache POI的
SXSSFWorkbook
),適合導出百萬級別數(shù)據(jù)量,但配置和使用會更復雜。
亮點來了,那要如何使用 POI 的 SXSSFWorkbook來導出百萬級別的數(shù)據(jù)量呢?
Apache POI的SXSSFWorkbook 實現(xiàn)百萬級別數(shù)據(jù)量的導出案例
使用Apache POI的SXSSFWorkbook
可以處理大數(shù)據(jù)量的Excel導出,因為SXSSFWorkbook
基于流式寫入,不會將所有數(shù)據(jù)加載到內存中,而是使用臨時文件進行緩存,這樣可以顯著減少內存消耗,適合百萬級別數(shù)據(jù)的導出。下面我們來看一個完整的實現(xiàn)示例。
代碼如下
import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class LargeDataExportExample { public static void main(String[] args) { // 文件輸出路徑 String filePath = "vg_large_data_export.xlsx"; // 導出百萬級數(shù)據(jù) exportLargeData(filePath); } private static void exportLargeData(String filePath) { // 每次寫入的批次大小 final int batchSize = 10000; // 數(shù)據(jù)總條數(shù) final int totalRows = 1_000_000; // 創(chuàng)建SXSSFWorkbook對象,內存中只保留100行,超過的部分會寫入臨時文件 SXSSFWorkbook workbook = new SXSSFWorkbook(100); workbook.setCompressTempFiles(true); // 啟用臨時文件壓縮 // 創(chuàng)建工作表 Sheet sheet = workbook.createSheet("Large Data"); // 創(chuàng)建標題行 Row headerRow = sheet.createRow(0); String[] headers = {"ID", "Name", "Age"}; for (int i = 0; i < headers.length; i++) { Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); } int rowNum = 1; // 數(shù)據(jù)開始的行號 try { // 按批次寫入數(shù)據(jù) for (int i = 0; i < totalRows / batchSize; i++) { // 模擬獲取每批數(shù)據(jù) List<Data> dataList = getDataBatch(rowNum, batchSize); // 將數(shù)據(jù)寫入到Excel中 for (Data data : dataList) { Row row = sheet.createRow(rowNum++); row.createCell(0).setCellValue(data.getId()); row.createCell(1).setCellValue(data.getName()); row.createCell(2).setCellValue(data.getAge()); } // 處理完成一批數(shù)據(jù)后,可以選擇清除緩存數(shù)據(jù),防止內存溢出 ((SXSSFSheet) sheet).flushRows(batchSize); // 清除已寫的行緩存 } // 將數(shù)據(jù)寫入文件 try (FileOutputStream fos = new FileOutputStream(filePath)) { workbook.write(fos); } System.out.println("數(shù)據(jù)導出完成:" + filePath); } catch (IOException e) { e.printStackTrace(); } finally { // 關閉workbook并刪除臨時文件 workbook.dispose(); } } /** * 模擬分頁獲取數(shù)據(jù) */ private static List<Data> getDataBatch(int startId, int batchSize) { List<Data> dataList = new ArrayList<>(batchSize); for (int i = 0; i < batchSize; i++) { dataList.add(new Data(startId + i, "Name" + (startId + i), 20 + (startId + i) % 50)); } return dataList; } // 數(shù)據(jù)類 static class Data { private final int id; private final String name; private final int age; public Data(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public String getName() { return name; } public int getAge() { return age; } } }
來解釋一下代碼
- SXSSFWorkbook:
SXSSFWorkbook(100)
表示內存中最多保留100行數(shù)據(jù),超過的部分會寫入臨時文件,節(jié)省內存。 - 批次處理:通過
batchSize
控制每批次寫入的數(shù)據(jù)量,以減少內存消耗。totalRows
設置為1,000,000表示導出100萬條數(shù)據(jù)。 - 模擬數(shù)據(jù)生成:
getDataBatch
方法模擬分頁獲取數(shù)據(jù),每次返回一批數(shù)據(jù)。 - 清除緩存行:每次寫入一批數(shù)據(jù)后,通過
flushRows(batchSize)
將緩存的行從內存中清除,以控制內存占用。 - 壓縮臨時文件:
workbook.setCompressTempFiles(true)
啟用臨時文件壓縮,進一步減少磁盤空間占用。
需要注意的事項
- 臨時文件:SXSSFWorkbook會在系統(tǒng)臨時文件夾中生成臨時文件,需要確保磁盤空間足夠。
- 資源釋放:完成數(shù)據(jù)寫入后需要調用
workbook.dispose()
以清理臨時文件。 - 性能優(yōu)化:可根據(jù)機器內存調整
batchSize
和SXSSFWorkbook
緩存行數(shù),避免頻繁刷新和內存溢出。
以上就是Java EasyExcel導出報內存溢出的解決辦法的詳細內容,更多關于Java EasyExcel導出內存溢出的資料請關注腳本之家其它相關文章!
相關文章
IDEA修改idea64.exe.vmoptions文件以及解決coding卡頓問題
IDEA修改idea64.exe.vmoptions文件以及解決coding卡頓問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04全網(wǎng)最深分析SpringBoot MVC自動配置失效的原因
這篇文章主要介紹了全網(wǎng)最深分析SpringBoot MVC自動配置失效的原因,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07詳解Javaweb狀態(tài)管理的Session和Cookie
這篇文章主要介紹了Javaweb狀態(tài)管理的Session和Cookie,將瀏覽器與web服務器之間多次交互當做一個整體來處理,并且多次交互所涉及的數(shù)據(jù)(狀態(tài))保存下來,需要的朋友可以參考下2023-05-05關于Spring MVC在Controller層中注入request的坑詳解
這篇文章主要給大家介紹了關于Spring MVC在Controller層中注入request的坑的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-04-04