SpringBoot 使用 POI 处理 40 万行 Excel 数据时内存溢出解决方案
在处理大数据量的 Excel 时,避免内存溢出的一种解决方案是使用 SAX 方式解析 Excel 文件,而不是使用 POI 的 DOM 方式。
SAX 是一种事件驱动的解析方式,它逐行读取 Excel 文件,而不是将整个文件加载到内存中。这样可以大大减少内存的使用量。
以下是使用 SAX 方式解析 Excel 文件的示例代码:
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class ExcelParser {
private static final int BATCH_SIZE = 1000; // 批量处理的行数
public static void parseExcel(InputStream inputStream) throws Exception {
OPCPackage opcPackage = OPCPackage.open(inputStream);
XSSFReader xssfReader = new XSSFReader(opcPackage);
SharedStringsTable sharedStringsTable = xssfReader.getSharedStringsTable();
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
ContentHandler contentHandler = new ExcelSheetHandler(sharedStringsTable);
xmlReader.setContentHandler(contentHandler);
SheetIterator sheetIterator = (SheetIterator) xssfReader.getSheetsData();
while (sheetIterator.hasNext()) {
InputStream sheetInputStream = sheetIterator.next();
InputSource inputSource = new InputSource(sheetInputStream);
xmlReader.parse(inputSource);
sheetInputStream.close();
}
opcPackage.close();
}
private static class ExcelSheetHandler extends DefaultHandler {
private SharedStringsTable sharedStringsTable;
private List<String> rowValues;
private int rowNum;
public ExcelSheetHandler(SharedStringsTable sharedStringsTable) {
this.sharedStringsTable = sharedStringsTable;
this.rowValues = new ArrayList<>();
this.rowNum = 0;
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
if (name.equals('row')) {
rowValues.clear();
rowNum++;
} else if (name.equals('c')) {
String cellType = attributes.getValue('t');
if (cellType != null && cellType.equals('s')) {
rowValues.add(sharedStringsTable.getItem(Integer.parseInt(attributes.getValue('v'))).getString());
}
}
}
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
if (name.equals('row') && rowNum % BATCH_SIZE == 0) {
// 处理一批数据
processBatchData(rowValues);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// 处理单元格数据
rowValues.add(new String(ch, start, length));
}
}
private static void processBatchData(List<String> rowValues) {
// 在这里处理一批数据,可以将数据写入数据库或进行其他操作
System.out.println(rowValues);
}
}
使用上述代码,可以按照自己的需求进行处理一批数据(比如将数据写入数据库)。
需要注意的是,上述代码仅适用于处理 XLSX 格式的 Excel 文件,如果需要处理 XLS 格式的 Excel 文件,可以使用 HSSF 方式进行解析。
另外,如果仍然遇到内存溢出的问题,可以考虑增加 JVM 的内存限制,即通过 -Xmx 参数设置 JVM 的最大堆内存大小。例如,可以使用以下命令运行应用程序:
java -Xmx2g -jar your-application.jar
上述命令将 JVM 的最大堆内存大小限制为 2GB。根据实际情况,可以根据需要适当调整内存大小。
原文地址: https://www.cveoy.top/t/topic/qgEI 著作权归作者所有。请勿转载和采集!