Java POI處理大型excel文件效率優(yōu)化策略
使用Java POI處理大型Excel文件時(shí),常常面臨讀取速度緩慢的問題,甚至可能導(dǎo)致內(nèi)存溢出錯(cuò)誤。這是因?yàn)镻OI默認(rèn)將整個(gè)文件加載到內(nèi)存中。本文將介紹兩種主流優(yōu)化方法,有效提升大型Excel文件讀取效率。
核心問題:內(nèi)存占用過高
POI默認(rèn)加載整個(gè)Excel文件到內(nèi)存,大型文件會(huì)導(dǎo)致內(nèi)存占用過高,嚴(yán)重影響讀取速度,甚至引發(fā)OutOfMemoryError。因此,需要采用分段讀取策略,避免一次性加載整個(gè)文件。
立即學(xué)習(xí)“Java免費(fèi)學(xué)習(xí)筆記(深入)”;
優(yōu)化方案:
方案一:使用xlsx-streamer庫(kù)實(shí)現(xiàn)分段讀取
xlsx-streamer基于POI,通過分段緩存機(jī)制,將數(shù)據(jù)分批加載到內(nèi)存,顯著降低內(nèi)存占用。它在創(chuàng)建Workbook對(duì)象時(shí)使用StreamingReader創(chuàng)建緩沖區(qū),批量讀取文件內(nèi)容。
首先,引入xlsx-streamer和poi-ooxml依賴:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>com.monitorjbl</groupId> <artifactId>xlsx-streamer</artifactId> <version>2.1.0</version> </dependency>
以下代碼演示如何使用xlsx-streamer讀取大型Excel文件:
public static void readLargeExcel(File file) throws Exception { InputStream inputStream = new FileInputStream(file); long start = System.currentTimeMillis(); try (Workbook workbook = StreamingReader.builder() .rowCacheSize(10000) // 緩存行數(shù) .bufferSize(4096) // 緩沖區(qū)大小 .open(inputStream)) { Sheet sheet = workbook.getSheetAt(0); log.info("Excel讀取完成,耗時(shí):{}毫秒", System.currentTimeMillis() - start); for (Row row : sheet) { System.out.println("讀取第" + row.getRowNum() + "行數(shù)據(jù):"); for (Cell cell : row) { System.out.print(cell.getStringCellValue() + " "); } System.out.println(); } System.out.println("讀取結(jié)束行數(shù):" + sheet.getLastRowNum()); } }
在處理數(shù)十萬行數(shù)據(jù)時(shí),此方法能顯著縮短讀取時(shí)間。
方案二:使用EasyExcel庫(kù)
EasyExcel是阿里巴巴開源的高效Excel處理工具,基于POI進(jìn)行了優(yōu)化,有效避免大文件讀取內(nèi)存溢出。它提供簡(jiǎn)潔的API,方便進(jìn)行讀寫操作。
添加EasyExcel依賴:
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.0</version> </dependency>
以下代碼演示如何使用EasyExcel讀取Excel文件,提供兩種讀取方式:對(duì)象封裝和map讀?。?/p>
public static void readExcelByEasyExcel(File file) { long start = System.currentTimeMillis(); List<ExcelData> excelDataList = EasyExcel.read(file).head(ExcelData.class).sheet(0).doReadSync(); excelDataList.forEach(System.out::println); log.info("Excel讀取完成,耗時(shí):{}毫秒", System.currentTimeMillis() - start); } public static void readExcelByEasyExcel1(File file) { long start = System.currentTimeMillis(); List<Map<String, Object>> listMap = EasyExcel.read(file).sheet(0).doReadSync(); listMap.forEach(x -> System.out.println(JSON.toJSONString(x))); log.info("Excel讀取完成,耗時(shí):{}毫秒", System.currentTimeMillis() - start); }
選擇哪種方案取決于具體需求和項(xiàng)目環(huán)境。xlsx-streamer側(cè)重于POI增強(qiáng),EasyExcel提供更全面的功能和更友好的API。 根據(jù)實(shí)際情況選擇最合適的方案。