如何使用POI库加载大型XLSX文件并解决内存溢出问题
如何使用POI库加载大型XLSX文件并解决内存溢出问题
兄弟,我太懂你这种加载大Excel文件崩溃的痛苦了!你用的XSSFWorkbook是把整个XLSX文件全塞进内存里解析,你这30万行150列的数据,算下来总单元格数都快5亿了,内存不爆才怪。别慌,POI其实早就考虑到这种场景了,给你几个靠谱的解决方案:
1. 用SXSSFWorkbook做流式处理(推荐,适合读写操作)
SXSSF是POI专门为处理大型Excel文件设计的,它会把超出指定行数的数据写到临时磁盘文件里,只把最近的N行留在内存中,内存占用瞬间降下来。
举个简单的例子:
// 设置内存中保留100行数据,超出的写入临时文件 SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 读取目标文件 FileInputStream fis = new FileInputStream(EXCELFILEPATH); workbook = new SXSSFWorkbook(new XSSFWorkbook(fis)); // 后续操作和XSSFWorkbook一致,比如获取工作表、遍历行数据 Sheet sheet = workbook.getSheetAt(0); for (Row row : sheet) { // 处理每行的单元格数据 } // 用完务必清理临时文件,避免磁盘空间浪费 workbook.dispose(); fis.close();
这种方法几乎不用改太多原有代码,就能大幅降低内存使用,适合需要对Excel进行修改或者写入的场景。
2. 用SAX事件驱动解析(适合仅读取数据的场景)
如果你的需求只是读取数据,不需要修改,那SAX解析是更极致的方案——它逐行逐单元格解析文件,完全不把整个文档加载到内存里,内存占用极低。
你需要自定义一个ContentHandler来处理解析事件,比如:
XMLReader reader = XMLReaderFactory.createXMLReader(); XSSFSheetHandler handler = new XSSFSheetHandler(); reader.setContentHandler(handler); // 读取XLSX的核心内容文件(需先解压XLSX找到xl/worksheets/sheet1.xml) InputStream is = new FileInputStream("xl/worksheets/sheet1.xml"); InputSource source = new InputSource(is); reader.parse(source);
自定义的XSSFSheetHandler需要继承DefaultHandler,重写startElement、endElement等方法,在这些方法里捕捉行和单元格的开始/结束事件,提取所需数据。这种方法代码量稍大,但内存占用是最小的。
3. 临时应急:调整JVM堆内存参数
如果只是临时救急,你可以在启动Java程序时加大堆内存,比如:
java -Xmx20G YourMainClass
但这只是治标不治本,文件再大一点还是会爆内存,所以优先推荐前两种方法。
另外再提个小技巧:如果只需要处理文件中的特定列或者特定行,在解析的时候直接过滤掉不需要的数据,能进一步减少内存压力。
备注:内容来源于stack exchange,提问作者Lyrk
相关产品推荐
相关产品推荐

