Apache POI与easyExcel:Excel文件导入导出的技术深度分析

简介: Apache POI与easyExcel:Excel文件导入导出的技术深度分析

一、Apache POI:全面但重量级的解决方案

Apache POI是一个历史悠久且功能全面的开源项目,用于处理Microsoft Office格式文件,包括Excel。它提供了对Excel文件读写操作的全面支持,在处理Excel文件时,POI通过HSSF和XSSF两个子项目分别支持.xls和.xlsx格式。HSSF针对的是旧版的二进制Excel格式,而XSSF则是为新版的基于XML的Excel格式设计的。


在导入Excel文件时,Apache POI会将整个文件加载到内存中,然后提供API来访问和操作文件中的各个元素,如单元格、行、列等。这种处理方式在处理小型文件时非常有效,因为它允许开发者以任意方式访问文件内容。然而,随着文件大小的增加,内存消耗也会急剧增长,这可能导致性能下降甚至内存溢出。


导出Excel文件时,Apache POI同样需要将所有数据加载到内存中,然后一次性写入文件。这种方式在处理大量数据时可能会变得非常缓慢,并且需要大量的内存资源。

1.1 POI实现读取excel

下面是一演示如何使用 Apache POI 导入(读取)和导出(写入)Excel 文件(.xlsx 格式)

<dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi</artifactId>  
    <version>5.2.0</version>  
</dependency>  
<dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi-ooxml</artifactId>  
    <version>5.2.0</version>  
</dependency>

开一个Excel文件、读取数据,并将内容打印到控制台上:

import org.apache.poi.ss.usermodel.*;  
import org.apache.poi.xssf.usermodel.XSSFWorkbook;  
  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.IOException;  
  
public class ExcelReaderExample {  
  
    public static void main(String[] args) {  
        // 指定要读取的Excel文件路径  
        String filePath = "path/to/your/excel/file.xlsx";  
  
        // 使用FileInputStream打开文件  
        try (FileInputStream fis = new FileInputStream(new File(filePath))) {  
  
            // 创建工作簿对象  
            Workbook workbook = new XSSFWorkbook(fis);  
  
            // 获取第一个工作表(Sheet),索引从0开始  
            Sheet sheet = workbook.getSheetAt(0);  
  
            // 遍历工作表的每一行  
            for (Row row : sheet) {  
                // 遍历行中的每一个单元格  
                for (Cell cell : row) {  
                    // 读取单元格内容并打印到控制台  
                    System.out.print(getCellValue(cell) + "\t");  
                }  
                // 每读取完一行后换行  
                System.out.println();  
            }  
  
            // 工作完成,关闭工作簿(实际上在这个例子中不需要,因为使用了try-with-resources)  
            // workbook.close();  
  
        } catch (IOException e) {  
            // 处理文件读取过程中可能出现的异常  
            e.printStackTrace();  
        }  
    }  
  
    // 辅助方法:根据单元格类型获取单元格的值  
    private static String getCellValue(Cell cell) {  
        DataFormatter formatter = new DataFormatter(); // 创建一个格式化对象,用于处理各种数据类型  
        return formatter.formatCellValue(cell); // 返回格式化后的单元格内容  
    }  
}


请注意,getCellValue方法使用DataFormatter类来确保无论单元格包含何种类型的数据(如数字、日期或文本),都能以合适的格式返回其字符串表示形式。

1.2 poi实现写入excel

当使用Apache POI写入.xlsx格式的Excel文件时,您需要创建一个XSSFWorkbook对象来表示整个工作簿,然后在其中创建XSSFSheet对象来表示工作表。接下来,您可以在工作表中创建行和单元格,并设置它们的值。最后,将工作簿写入到文件系统中。

import org.apache.poi.ss.usermodel.*;  
import org.apache.poi.xssf.usermodel.XSSFWorkbook;  
  
import java.io.FileOutputStream;  
import java.io.IOException;  
  
public class ExcelWriterExample {  
  
    public static void main(String[] args) {  
        // 创建一个新的工作簿  
        Workbook workbook = new XSSFWorkbook();  
  
        // 创建一个工作表(Sheet),命名为"MySheet"  
        Sheet sheet = workbook.createSheet("MySheet");  
  
        // 在工作表中创建行(从0开始计数)  
        Row row = sheet.createRow(0);  
  
        // 在行中创建单元格(从0开始计数),并设置值  
        Cell cell = row.createCell(0);  
        cell.setCellValue("Hello");  
  
        // 创建另一个单元格,并设置值  
        Cell cell2 = row.createCell(1);  
        cell2.setCellValue("World");  
  
        // 也可以链式地创建行和单元格  
        sheet.createRow(1).createCell(0).setCellValue("Apache");  
        sheet.getRow(1).createCell(1).setCellValue("POI");  
  
        // 写入到文件系统  
        try (FileOutputStream fos = new FileOutputStream("path/to/your/excel/file.xlsx")) {  
            workbook.write(fos);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
  
        // 关闭工作簿(在这个例子中不需要,因为使用了try-with-resources)  
        // workbook.close();  
  
        System.out.println("Excel file written successfully.");  
    }  
}

二、easyExcel:轻量级且高效的Excel处理工具

easyExcel是阿里巴巴开源的一个轻量级且高效的Excel处理框架。它针对大型Excel文件的处理进行了优化,采用了流式处理的方式,允许开发者逐行读写数据,从而大大降低了内存消耗。在导入Excel文件时,easyExcel使用了基于事件驱动的模型。它不会将整个文件加载到内存中,而是逐行解析文件,通过回调函数将每行的数据传递给开发者进行处理。

EasyExcel 是在在POI的解析引擎基础上改进的,但并没有完全重写 Apache POI 的整个解析引擎,特别是对于 XLSX 文件格式(即 Excel 2007 及以上版本所使用的格式,POI 中对应的是 XSSF 实现),它仍然是基于 POI 的一些底层结构和功能。但是,EasyExcel 在 POI 的基础上进行了大量的优化和重构,以实现更高的性能和更低的内存消耗。

2.1 EasyExcel 做的优化

EasyExcel 的核心改进之一是在处理大型数据时采用了“读写分离”和“懒加载”的策略。具体来说,EasyExcel 做了以下几点优化:

按需解析:EasyExcel 不会一次性将整个文件加载到内存中,而是按需读取和解析数据,通过滑动窗口的方式只处理当前需要的数据行,从而大大降低了内存占用。


写入优化:在写入数据时,EasyExcel 同样采用了流式写入的策略,将数据分批次写入磁盘,避免了大数据量时的内存溢出问题。


内存管理:EasyExcel 对内存的使用进行了精细化的管理,通过对象池、缓存优化等技术减少了内存分配和垃圾回收的频率,提升了处理速度。


模型映射:通过注解和反射机制,EasyExcel 可以将 Excel 数据行直接映射为 Java 对象,简化了数据转换的过程。


异常处理:EasyExcel 提供了更加友好的异常处理机制,帮助开发者快速定位和处理读写过程中可能出现的问题。


扩展性:EasyExcel 设计了更加灵活和可扩展的架构,允许开发者通过实现特定的接口来定制和扩展功能。

尽管 EasyExcel 在 POI 的基础上进行了很多优化,但它仍然依赖于 POI 的一些核心组件来处理 XLSX 文件的底层细节。因此,在使用 EasyExcel 时,仍然可以看到 POI 的影子,尤其是在处理一些复杂的 Excel 特性时。不过,对于大多数常见的 Excel 读写需求,EasyExcel 提供了更加高效和简洁的解决方案。

2.2 easyExcel实现批量读取excel

将 easyExcel 的依赖添加到了你的项目中。如果使用 Maven,可以在 pom.xml 文件中添加如下依赖:

<dependency>  
    <groupId>com.alibaba</groupId>  
    <artifactId>easyexcel</artifactId>  
    <version>最新版本</version> <!-- 请替换为实际的最新版本号 -->  
</dependency>

使用easyExcel的读取API,并指定要读取的sheet索引(从0开始计数,第二个sheet的索引为1)。

实现一个监听器来处理读取到的数据行,并在这个监听器中将数据分批写入数据库。

import com.alibaba.excel.EasyExcel;  
import com.alibaba.excel.context.AnalysisContext;  
import com.alibaba.excel.event.AnalysisEventListener;  
import com.alibaba.excel.read.builder.ExcelReaderBuilder;  
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;  
import com.alibaba.excel.read.metadata.ReadSheet;  
  
import java.util.ArrayList;  
import java.util.List;  
  
// 数据模型类  
class DataModel {  
    private String column1;  
    private String column2;  
    // ... 其他字段  
  
    // 省略getter和setter方法  
}  
  
// 读取Excel并写入数据库的类  
public class ExcelReaderToDB {  
  
    // 模拟的批量写入数据库方法  
    private void batchInsertToDB(List<DataModel> dataList) {  
        // 这里应该是将数据真正写入数据库的代码  
        // 这里仅做打印输出模拟  
        System.out.println("Inserting batch of " + dataList.size() + " rows to DB...");  
        for (DataModel data : dataList) {  
            System.out.println(data);  
        }  
    }  
  
    // 读取Excel文件的方法  
    public void readExcelFile(String filePath) {  
        // 第二个sheet的索引为1  
        int sheetIndex = 1;  
  
        // 读取Excel文件  
        ExcelReaderBuilder readerBuilder = EasyExcel.read(filePath);  
        ExcelReaderSheetBuilder sheetBuilder = readerBuilder.sheet(sheetIndex);  
  
        // 读取数据并注册监听器  
        sheetBuilder.registerReadListener(new AnalysisEventListener<DataModel>() {  
            // 用来缓存读取到的数据  
            private List<DataModel> cachedDataList = new ArrayList<>();  
  
            // 读取每行数据时会调用此方法  
            @Override  
            public void invoke(DataModel dataModel, AnalysisContext analysisContext) {  
                cachedDataList.add(dataModel);  
                // 当读取到一定数量的数据时,可以执行批量写入数据库的操作  
                // 这里假设我们每读取100行数据就写入一次数据库  
                if (cachedDataList.size() >= 100) {  
                    batchInsertToDB(cachedDataList);  
                    // 清空缓存  
                    cachedDataList.clear();  
                }  
            }  
  
            // 所有数据解析完成后会调用此方法  
            @Override  
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {  
                // 将剩余的数据写入数据库  
                if (!cachedDataList.isEmpty()) {  
                    batchInsertToDB(cachedDataList);  
                    cachedDataList.clear();  
                }  
            }  
        });  
  
        // 开始读取  
        sheetBuilder.build();  
        readerBuilder.build().read();  
    }  
  
    public static void main(String[] args) {  
        String filePath = "path/to/your/excel/file.xlsx";  
        ExcelReaderToDB excelReader = new ExcelReaderToDB();  
        excelReader.readExcelFile(filePath);  
    }  
}

2.3 easyExcel实现写入excel

定义一个模型类来表示你要写入的数据。创建一个数据模型类来映射Excel表格中的数据列,并使用easyExcel的注解来标识表头和字段映射关系。

编写一个方法来创建Excel写入对象,并填充数据到Excel文件中.

import com.alibaba.excel.EasyExcel;  
import com.alibaba.excel.write.metadata.WriteSheet;  
import com.alibaba.excel.annotation.ExcelProperty;  
  
import java.util.ArrayList;  
import java.util.List;  
  
// 数据模型类,使用注解标识表头和字段映射关系  
public class DataModel {  
  
    // 表头名称与字段的映射  
    @ExcelProperty("姓名")  
    private String name;  
  
    @ExcelProperty("年龄")  
    private Integer age;  
  
    // 省略getter和setter方法  
  
    // 构造函数  
    public DataModel(String name, Integer age) {  
        this.name = name;  
        this.age = age;  
    }  
}  
  
// 导出数据到Excel的类  
public class ExcelExporter {  
  
    // 模拟数据  
    private List<DataModel> getData() {  
        List<DataModel> list = new ArrayList<>();  
        list.add(new DataModel("张三", 20));  
        list.add(new DataModel("李四", 22));  
        list.add(new DataModel("王五", 24));  
        return list;  
    }  
  
    // 导出数据到Excel文件  
    public void exportToExcel(String filePath) {  
        // 创建写入对象  
        EasyExcel.write(filePath, DataModel.class)  
                .sheet("Sheet1") // 设置sheet名称  
                .doWrite(getData()); // 写入数据  
    }  
  
    public static void main(String[] args) {  
        String filePath = "path/to/your/excel/file.xlsx";  
        ExcelExporter exporter = new ExcelExporter();  
        exporter.exportToExcel(filePath);  
    }  
}

三、API设计与易用性

Apache POI提供了丰富且灵活的API,允许开发者以多种方式操作Excel文件。然而,由于其功能全面且复杂,API的学习曲线相对较陡,对于初学者来说可能需要一些时间来熟悉。

相比之下,easyExcel的API设计更加简洁和直观。它提供了针对常见任务的简化方法,使得开发者能够更快速地完成任务。此外,easyExcel还支持自定义读写策略、异步处理、数据校验等高级特性,这些功能都通过简洁的API暴露给开发者,提高了易用性。

四、总结

Apache POI和easyExcel都是优秀的Java库,用于处理Excel文件。Apache POI以其全面性和灵活性著称,提供了对Excel文件的全面支持。然而,在处理大型文件时,它可能会遇到性能问题和内存消耗过高的情况。相比之下,easyExcel则针对大型文件的处理进行了优化,提供了更高的性能和更低的内存消耗。此外,easyExcel的API设计更加简洁和易用,使得开发者能够更高效地完成任务。


在选择使用哪个库时,开发者应根据项目需求和文件大小来决定。如果项目需要处理大型Excel文件,并且对性能和内存消耗有较高要求,那么easyExcel可能是一个更好的选择。而如果项目需要全面的Excel文件处理功能,并且对性能要求不高,那么Apache POI也是一个不错的选择。


相关文章
|
6月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
1261 65
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
8月前
|
easyexcel Java UED
SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
在SpringBoot环境中,为了优化大量数据的Excel导出体验,可采用异步方式处理。具体做法是将数据拆分后利用`CompletableFuture`与`ThreadPoolTaskExecutor`并行导出,并使用EasyExcel生成多个Excel文件,最终将其压缩成ZIP文件供下载。此方案提升了导出效率,改善了用户体验。代码示例展示了如何实现这一过程,包括多线程处理、模板导出及资源清理等关键步骤。
|
8月前
|
前端开发 JavaScript Java
导出excel的两个方式:前端vue+XLSX 导出excel,vue+后端POI 导出excel,并进行分析、比较
这篇文章介绍了使用前端Vue框架结合XLSX库和后端结合Apache POI库导出Excel文件的两种方法,并对比分析了它们的优缺点。
2162 0
|
8月前
|
Java Apache
Apache POI java对excel表格进行操作(读、写) 有代码!!!
文章提供了使用Apache POI库在Java中创建和读取Excel文件的详细代码示例,包括写入数据到Excel和从Excel读取数据的方法。
917 0
|
9月前
|
数据可视化 数据处理 Python
Python操作Excel:轻松实现数据处理与分析
Python操作Excel:轻松实现数据处理与分析
478 0
|
10月前
|
easyexcel Java 关系型数据库
阿里巴巴-EasyExcel 基于Java的简单、省内存的读写Excel
该文章主要介绍了在Java应用中如何使用EasyExcel技术完成对Excel文件的导入和导出操作,包括环境搭建、基本概念、快速入门、进阶操作和综合应用等内容,并提供了相关代码示例和注意事项。
 阿里巴巴-EasyExcel 基于Java的简单、省内存的读写Excel
|
10月前
|
easyexcel Java API
Apache POI、EasyPoi、EasyExcel 三种区别,如何选择
Apache POI、EasyPoi、EasyExcel 三种区别,如何选择
1313 0
|
6月前
|
存储 人工智能 大数据
The Past, Present and Future of Apache Flink
本文整理自阿里云开源大数据负责人王峰(莫问)在 Flink Forward Asia 2024 上海站主论坛开场的分享,今年正值 Flink 开源项目诞生的第 10 周年,借此时机,王峰回顾了 Flink 在过去 10 年的发展历程以及 Flink社区当前最新的技术成果,最后展望下一个十年 Flink 路向何方。
560 33
The Past, Present and Future of Apache Flink
|
8月前
|
SQL Java API
Apache Flink 2.0-preview released
Apache Flink 社区正积极筹备 Flink 2.0 的发布,这是自 Flink 1.0 发布以来的首个重大更新。Flink 2.0 将引入多项激动人心的功能和改进,包括存算分离状态管理、物化表、批作业自适应执行等,同时也包含了一些不兼容的变更。目前提供的预览版旨在让用户提前尝试新功能并收集反馈,但不建议在生产环境中使用。
1354 13
Apache Flink 2.0-preview released
|
3月前
|
SQL 存储 人工智能
Apache Flink 2.0.0: 实时数据处理的新纪元
Apache Flink 2.0.0 正式发布!这是自 Flink 1.0 发布九年以来的首次重大更新,凝聚了社区两年的努力。此版本引入分离式状态管理、物化表、流批统一等创新功能,优化云原生环境下的资源利用与性能表现,并强化了对人工智能工作流的支持。同时,Flink 2.0 对 API 和配置进行了全面清理,移除了过时组件,为未来的发展奠定了坚实基础。感谢 165 位贡献者的辛勤付出,共同推动实时计算进入新纪元!
414 1
Apache Flink 2.0.0: 实时数据处理的新纪元

热门文章

最新文章

推荐镜像

更多