使用Apache POI读取超150MB大Excel文件时线程阻塞求助
大文件Excel读取异常:Apache POI无法生成Workbook
使用Apache POI进行Excel读写时,小文件处理正常,但读取150MB+、包含20万+条记录的文件时,线程持续运行却始终无法返回Workbook对象,无法执行后续操作。
调试日志
2022-11-29 17:04:33.541 DEBUG 33576 --- [ecutor-thread-8] o.a.p.o.o.PackageRelationshipCollection : Parsing relationship: /xl/pivotCache/_rels/pivotCacheDefinition1.xml.rels 2022-11-29 17:04:33.604 DEBUG 33576 --- [ecutor-thread-8] o.a.p.o.o.PackageRelationshipCollection : Parsing relationship: /xl/pivotTables/_rels/pivotTable1.xml.rels 2022-11-29 17:04:33.631 DEBUG 33576 --- [ecutor-thread-8] o.a.p.o.o.PackageRelationshipCollection : Parsing relationship: /xl/_rels/workbook.xml.rels 2022-11-29 17:04:33.646 DEBUG 33576 --- [ecutor-thread-8] o.a.p.o.o.PackageRelationshipCollection : Parsing relationship: /xl/worksheets/_rels/sheet1.xml.rels 2022-11-29 17:04:33.657 DEBUG 33576 --- [ecutor-thread-8] o.a.p.o.o.PackageRelationshipCollection : Parsing relationship: /xl/worksheets/_rels/sheet2.xml.rels 2022-11-29 17:04:33.672 DEBUG 33576 --- [ecutor-thread-8] o.a.p.o.o.PackageRelationshipCollection : Parsing relationship: /_rels/.rels 2022-11-29 17:04:47.661 DEBUG 33576 --- [ecutor-thread-8] org.apache.poi.ooxml.POIXMLFactory : using default POIXMLDocumentPart for http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings 2022-11-29 17:04:47.666 DEBUG 33576 --- [ecutor-thread-8] org.apache.poi.ooxml.POIXMLFactory : using default POIXMLDocumentPart for http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings
使用的依赖
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>5.2.3</version> </dependency>
已尝试的方案
- 直接加载XSSFWorkbook:
Workbook workbook = new XSSFWorkbook(file);
- 基于XSSF创建SXSSFWorkbook:
SXSSFWorkbook workbook = new SXSSFWorkbook(new XSSFWorkbook(file));
- 使用WorkbookFactory创建:
Workbook workbook = WorkbookFactory.create(f);
不可用方案说明
以下方案因忽略空白单元格导致列读取异常,且受公司政策限制无法使用:
InputStream is = new FileInputStream(new File(uploadfilePath.toString())); Workbook workbook = StreamingReader.builder().rowCacheSize(100).bufferSize(4096).open(is);
可行解决方案
1. 跳过透视表缓存加载
从日志可见,POI在处理透视表缓存(pivotCache),这是大文件读取卡顿的核心原因之一。通过配置POI参数跳过透视表相关内容:
// 方式1:直接通过OPCPackage配置 OPCPackage pkg = OPCPackage.open(file); Map<String, Object> config = new HashMap<>(); // 禁用透视表缓存解析 config.put(XSSFWorkbook.SKIP_PIVOT_CACHE, true); XSSFWorkbook workbook = new XSSFWorkbook(pkg, config); // 方式2:使用WorkbookFactory Map<String, Object> params = new HashMap<>(); params.put("XSSF_PARSE_PIVOT_CACHE", false); Workbook workbook = WorkbookFactory.create(file, null, false, params);
2. 优化JVM内存参数
大文件读取需要足够的内存支撑,调整JVM启动参数(根据机器配置调整数值):
-Xms2G -Xmx4G -XX:+UseG1GC
-Xms设置初始内存,-Xmx设置最大内存,G1GC适合大内存场景的垃圾回收。
3. 正确使用SXSSF流式处理
避免先加载完整XSSFWorkbook,改用直接从流创建,并设置内存保留行数:
InputStream inputStream = new FileInputStream(file); XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream); // 仅保留100行在内存,超出部分写入临时磁盘文件 SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(xssfWorkbook, 100); // 处理完成后必须清理临时文件,避免磁盘占用 sxssfWorkbook.dispose();
4. 预处理Excel文件(若允许)
手动或通过工具删除Excel中不必要的透视表、冗余格式、空白行等内容,大幅减小文件体积后再读取,能显著提升POI的处理速度。
内容的提问来源于stack exchange,提问作者tara kantheti
相关产品推荐
相关产品推荐

