您的位置:

如何高效导入百万级数据?使用easyexcel!

一、什么是easyexcel?

EasyExcel是一个操作Excel的Java工具,主要用于读写大量数据时提高效率。它采用了基于流的操作方式,大大减少了内存消耗以及GC的次数。而且EasyExcel还有一些方便实用的功能,比如导出模板、数据校验等等。

二、为什么选择easyexcel?

在处理大量Excel数据时,传统的POI操作方式会出现诸多问题。因为POI需要一次性将整个Excel文件读入内存,如果excel文件过大,就会出现内存溢出导致程序崩溃。而easyexcel则通过内部自定义的回调方式,可以避免过多存储Excel数据而占用过多的内存。

而且EasyExcel还支持多种格式的数据导入和导出,包括Excel、Csv、Pdf和Html等等。这些功能都使得easyexcel成为处理Excel数据的首选工具。

三、如何使用easyexcel导入百万级数据?

我们来看一个简单的示例:

public void readExcel(){
    InputStream inputStream = null;
    try {
        inputStream = new FileInputStream("test.xlsx");
        // 构建读取实体类
        ExcelListener listener = new ExcelListener();
        ExcelReader excelReader = new ExcelReader(inputStream, null, listener);
        excelReader.read();
        List<Object> list = listener.getList();
        // TODO: 对数据进行处理
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

上述代码中,我们通过创建一个ExcelReader对象,然后传入Excel数据流、读取sheet的索引以及自定义的ExcelListener类实例。然后调用read()方法就可以读取到Excel文件中的所有数据。

但是实际上,我们一般不会将所有数据都读取到内存中,因为这样会占用大量内存并且运行缓慢。而是将数据分批读取,每次读取一定量的数据到内存中进行处理,然后再读取下一批数据。这样可以使得程序处理速度更快而且更加稳定。

下面是一个使用easyexcel分批读取百万级数据的示例代码:

public void batchReadExcel() {
    InputStream inputStream = null;
    try {
        inputStream = new FileInputStream("test.xlsx");
        ExcelListener listener = new ExcelListener();
        // 批量处理数据每次读取1000条数据
        AnalysisEventListener<Object> batchListener = new AnalysisEventListener<Object>() {

            private static final int BATCH_COUNT = 1000;
            // 自定义数据处理逻辑, 每读取1000条数据进行一次处理
            List<Object> list = new ArrayList<Object>(BATCH_COUNT);
            public void invoke(Object object, AnalysisContext context) {
                list.add(object);
                if (list.size() >= BATCH_COUNT) {
                    // TODO: 对数据进行处理
                    list.clear();
                }
            }

            public void doAfterAllAnalysed(AnalysisContext context) {
                // TODO: 处理最后一次的数据
            }
        };

        ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
        ExcelReader excelReader = excelReaderBuilder
            .file(inputStream)
            .readAll()
            .headRowNumber(1)
            .excelType(ExcelTypeEnum.XLSX)
            .registerReadListener(batchListener)
            .build();
        excelReader.read();
    } catch (FileNotFoundException e) {
        // TODO: 异常处理
    } finally {
        try {
            inputStream.close();
        } catch (IOException e) {
            // TODO: 异常处理
        }
    }
}

在上述代码中,我们首先创建了一个批量处理的监听器,每次处理一定量的数据。然后通过ExcelReaderBuilder来创建ExcelReader实例,将输入流、读取所有sheet、指定Excel类型、批量处理监听器传入ExcelReaderBuilder中,最后调用build()方法创建ExcelReader实例,并调用read()方法进行读取。

四、如何实现数据校验?

EasyExcel内置了一些常用的数据校验功能。对于一些特殊的校验需求,可以通过继承EasyExcel内置的ConstraintValidator实现自定义校验规则。

下面是一个实现数据校验的示例代码:

public class ExcelListener extends AnalysisEventListener<Object> {

    private List<Object> list = new ArrayList<Object>();

    // 继承ConstraintValidator并实现自定义校验规则
    private ConstraintValidator constraintValidator;

    public ExcelListener(ConstraintValidator constraintValidator) {
        this.constraintValidator = constraintValidator;
    }

    @Override
    public void invoke(Object object, AnalysisContext context) {
        if(constraintValidator != null) {
            // 在读取Excel文件之前,对数据进行校验
            constraintValidator.validate(object);
        }
        list.add(object);
    }
    // 省略getter、setter方法
}

上述代码中,我们通过继承EasyExcel的AnalysisEventListener实现对Excel数据的监听。在invoke()方法中,我们可以将读取到的数据进行校验,然后将校验通过后的数据加入到列表中。

下面是一个自定义校验规则的示例代码:

public class CustomConstraintValidator implements ConstraintValidator {

    @Override
    public void validate(Object o) throws Exception {
        // TODO: 自定义校验逻辑
    }

    @Override
    public void addCondition(Condition condition) {

    }

    @Override
    public void init() {

    }

    @Override
    public void setParameters(Map<String, Object> map) {

    }

    @Override
    public void close() throws IOException {

    }
}

五、如何导出Excel数据到文件?

EasyExcel同样支持从Java对象中导出数据到Excel文件中,操作非常简单,只需要调用EasyExcel的write()方法,并传入数据和文件保存路径即可。

下面是一个导出Excel的示例代码:

public void writeExcel() {
    OutputStream outputStream = null;
    try {
        outputStream = new FileOutputStream("test.xlsx");

        // 准备导出数据
        List<Object> list = new ArrayList<Object>();
        // TODO: 添加数据到列表中

        // 导出Excel文件
        ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
        WriteSheet writeSheet = EasyExcel.writerSheet(0, "Sheet1").head(Object.class).build();
        excelWriter.write(list, writeSheet);
    } catch (IOException e) {
        // TODO: 异常处理
    } finally {
        try {
            outputStream.close();
        } catch (IOException e) {
            // TODO: 异常处理
        }
    }
}

上述代码中,我们首先创建一个输出流,然后准备要导出的数据,并创建ExcelWriter实例。调用EasyExcel的静态方法write(),并传入输出流即可实现创建ExcelWriter实例的功能。然后通过调用EasyExcel的writerSheet()方法来创建WriteSheet实例,并指定sheet的名称和要导出的数据类型,然后将数据和WriteSheet传入ExcelWriter的write()方法即可实现Excel数据的导出。