杰瑞科技汇

java导入大数据excel

Java导入大数据Excel解决方案

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

java导入大数据excel-图1
(图片来源网络,侵删)

使用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(",");
                // 处理每行数据
            }
        }
    }
}

分块读取策略

对于特别大的文件,可以分块读取:

java导入大数据excel-图2
(图片来源网络,侵删)
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);
            // 处理行数据
        }
    }
}

性能优化建议

  1. 禁用公式计算workbook.setForceFormulaRecalculation(false)
  2. 关闭自动过滤sheet.setAutoFilter(null)
  3. 使用SXSSFWorkbook:对于.xlsx格式,使用流式API
  4. 调整JVM内存:增加堆内存大小(-Xmx参数)
  5. 并行处理:将数据分块后多线程处理

注意事项

  • 对于.xlsx格式,POI的SAX模式比DOM模式内存效率高
  • 对于.xls格式,POI的HSSF不支持SAX模式,只能使用分块读取
  • 确保正确处理文件流和资源释放
  • 考虑使用数据库临时表存储中间结果

选择哪种方法取决于你的具体需求、文件大小和性能要求,对于特别大的文件(GB级别),建议使用EasyExcel或POI的SAX模式。

分享:
扫描分享到社交APP
上一篇
下一篇