读取大数据量excel文件——poi的事件驱动模式

一、适用场景

       使用poi读取excel文件有两种方式,一种是用户模式,使用封装好的api操作excel文件。这种模式读取excel文件中的数据会一次性将文件中的内容读取到内存中,虽使用方便,但是当文件数据够大时,会出现内存溢出。这种情况下可以用poi的事件驱动,基于sax的读取方式读取excel文件。

二、poi事件驱动

       poi的时间驱动,是区别于用户模式的另一种解析方式,原理是逐行读取excel文件(仅限于excel2007以上版本),在开始读取一行时初始化对象,并在读取每个单元格时给对象赋值,在一行读取结束后将对象加入到一个集合中,以此来实现在大数据量的情况下顺利完成数据读取。

三、代码

1.核心的解析处理器

import com.bigsea.entity.Employee;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义sheet基于Sax的解析处理器
 */
public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler {
    // 封装实体对象
    private Employee employee;
    // 集合对象
    private List<Employee> employeeList;

    /**
     * 当开始解析某一行的时候触发
     * @param i 行号
     */
    @Override
    public void startRow(int i) {
        if (i > 0) {
            employee = new Employee();
        }
    }

    /**
     * 当结束解析某一行的时候触发
     * @param i 行号
     */
    @Override
    public void endRow(int i) {
        if (employeeList == null) {
            employeeList = new ArrayList<>();
        }
        employeeList.add(employee);
        // 当list集合大小为1000时,执行插入,并初始化集合对象(此处为伪操作)
        if (employeeList.size() == 1000) {
            System.out.println(employeeList.size());
            employeeList = new ArrayList<>();
        }
    }

    /**
     * 对行中的每一个单元格进行处理
     * @param cellName 单元格名称
     * @param value 数据
     * @param xssfComment 批注
     */
    @Override
    public void cell(String cellName, String value, XSSFComment xssfComment) {
        if (employee != null) {
            String prefix = cellName.substring(0, 1);
            switch (prefix) {
                case "A":
                    employee.setCode(Integer.valueOf(value));
                    break;
                case "B":
                    employee.setName(value);
                    break;
                case "C":
                    employee.setSex(value);
                    break;
                case "D":
                    employee.setDept(value);
                    break;
                case "E":
                    employee.setPosition(value);
                    break;
                case "F":
                    employee.setLeaderName(value);
                    break;
                case "G":
                    employee.setSalary(Double.valueOf(value));
                    break;
                case "H":
                    employee.setInDateStr(value);
                    break;
                case "I":
                    employee.setHolidayCount(Integer.valueOf(value));
                    break;
            }
        }
    }
}

2.在业务层调用sax解析处理器

import com.bigsea.service.ImportExcelService;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.springframework.stereotype.Service;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import java.io.InputStream;

/**
 * 导入excel文件业务层
 * excel读取有两种方式
 * 1.用户模式:使用系列封装好的api操作excel
 * 2.事件驱动:基于sax的读取方式读取excel的xml文件
 */
@Service
public class ImportServiceImpl implements ImportExcelService {
    /**
     * 读取大数据量excel
     * @parm path 文件路径
     */
    @Override
    public void readBigDataExcel(String path) throws Exception {
        // 1.根据excel报表获取OPCpackage
        OPCPackage opcPackage = OPCPackage.open(path, PackageAccess.READ);
        // 2.创建XSSFReader
        XSSFReader xssfReader = new XSSFReader(opcPackage);
        // 3.获取SharedStringTable对象
        SharedStringsTable sharedStringsTable = xssfReader.getSharedStringsTable();
        // 4.获取styleTable对象
        StylesTable stylesTable = xssfReader.getStylesTable();
        // 5.创建sax xmlReader对象
        XMLReader xmlReader = XMLReaderFactory.createXMLReader();
        // 6.注册事件驱动处理器
        XSSFSheetXMLHandler xssfSheetXMLHandler = new XSSFSheetXMLHandler(stylesTable, sharedStringsTable, new SheetHandler(), false);
        xmlReader.setContentHandler(xssfSheetXMLHandler);
        // 7.逐行读取
        XSSFReader.SheetIterator sheetIterator = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
        while (sheetIterator.hasNext()) {
            InputStream in = sheetIterator.next();
            InputSource is = new InputSource(in);
            xmlReader.parse(is);
        }
    }
}
发布了48 篇原创文章 · 获赞 52 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/y506798278/article/details/90725759