Java导入大数据Excel解决方案
在Java中处理大型Excel文件时,需要注意内存使用和性能问题,以下是几种处理大数据Excel的常用方法:

使用Apache POI的SAX模式(事件驱动)
对于非常大的Excel文件(超过100MB),推荐使用POI的SAX模式(XSSF and SAX (Event API)):
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class LargeExcelReader {
public void processLargeExcel(String filePath) throws Exception {
try (OPCPackage pkg = OPCPackage.open(filePath)) {
XSSFReader r = new XSSFReader(pkg);
SharedStringsTable sst = r.getSharedStringsTable();
XMLReader parser = XMLReaderFactory.createXMLReader();
parser.setContentHandler(new SheetHandler(sst));
parser.parse(new InputSource(r.getSheet("rId1")));
}
}
}
class SheetHandler extends DefaultHandler {
private SharedStringsTable sst;
private String lastContents;
private boolean nextIsString;
public SheetHandler(SharedStringsTable sst) {
this.sst = sst;
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) {
if (name.equals("c")) {
String cellType = attributes.getValue("t");
if (cellType != null && cellType.equals("s")) {
nextIsString = true;
} else {
nextIsString = false;
}
}
lastContents = "";
}
@Override
public void endElement(String uri, String localName, String name) {
if (nextIsString) {
int idx = Integer.parseInt(lastContents);
lastContents = sst.getItemAt(idx).getString();
nextIsString = false;
}
if (name.equals("v")) {
// 处理单元格值
System.out.println(lastContents);
}
}
@Override
public void characters(char[] ch, int start, int length) {
lastContents += new String(ch, start, length);
}
}
使用EasyExcel(阿里巴巴开源库)
EasyExcel是基于POI封装的库,对大数据处理做了优化:
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
public class EasyExcelExample {
public static void main(String[] args) {
String fileName = "large.xlsx";
EasyExcel.read(fileName, YourDataModel.class, new AnalysisEventListener<YourDataModel>() {
@Override
public void invoke(YourDataModel data, AnalysisContext context) {
// 处理每行数据
System.out.println(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 所有数据解析完成后的操作
}
}).sheet().doRead();
}
}
使用CSV格式作为中间步骤
如果可能,将Excel转换为CSV格式处理:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CsvReader {
public void readLargeCsv(String filePath) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
String[] values = line.split(",");
// 处理每行数据
}
}
}
}
分块读取策略
对于特别大的文件,可以分块读取:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ChunkedExcelReader {
public void readInChunks(String filePath, int chunkSize) throws IOException {
try (Workbook workbook = new XSSFWorkbook(new FileInputStream(filePath))) {
Sheet sheet = workbook.getSheetAt(0);
int totalRows = sheet.getPhysicalNumberOfRows();
for (int i = 0; i < totalRows; i += chunkSize) {
int endRow = Math.min(i + chunkSize, totalRows);
// 处理从i到endRow的数据块
processChunk(sheet, i, endRow);
}
}
}
private void processChunk(Sheet sheet, int startRow, int endRow) {
for (int i = startRow; i < endRow; i++) {
Row row = sheet.getRow(i);
// 处理行数据
}
}
}
性能优化建议
- 禁用公式计算:
workbook.setForceFormulaRecalculation(false) - 关闭自动过滤:
sheet.setAutoFilter(null) - 使用SXSSFWorkbook:对于.xlsx格式,使用流式API
- 调整JVM内存:增加堆内存大小(
-Xmx参数) - 并行处理:将数据分块后多线程处理
注意事项
- 对于.xlsx格式,POI的SAX模式比DOM模式内存效率高
- 对于.xls格式,POI的HSSF不支持SAX模式,只能使用分块读取
- 确保正确处理文件流和资源释放
- 考虑使用数据库临时表存储中间结果
选择哪种方法取决于你的具体需求、文件大小和性能要求,对于特别大的文件(GB级别),建议使用EasyExcel或POI的SAX模式。
