使用 EasyExcel 读取Excel(两种方式)

本文详细介绍如何使用EasyExcel库进行Excel文件的读写操作,包括实体类注解的使用,同步与异步读取方法,以及如何处理大量数据以减少内存消耗。同时,提供了具体的代码示例和数据转换技巧。

转载:https://www.cnblogs.com/oukele/p/11443659.html

引入 jar 包

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>1.1.2-beta5</version>
        </dependency>

EasyExcel支持对实体类中的属性进行注解,方便后续进行读写操作。

 id 为 表头,index 代表的是 第0行

 @ExcelProperty(value="id",index=0)

新建一个 ExcelModel 实体(需要继承 BaseRowModel)

package com.zh.oukele.model;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;

/**
 * 表格实体
 */
public class ExcelMode extends BaseRowModel {

    /**
     * 第一列的数据
     */
    @ExcelProperty(index = 0)
    private String column1;
    /**
     * 第二列的数据
     */
    @ExcelProperty(index = 1)
    private String column2;

    public void setColumn1(String column1) {
        this.column1 = column1;
    }

    public String getColumn1() {
        return column1;
    }

    public String getColumn2() {
        return column2;
    }

    public void setColumn2(String column2) {
        this.column2 = column2;
    }

    @Override
    public String toString() {
        return "ExcelMode{" +
                "column1='" + column1 + '\'' +
                ", column2='" + column2 + '\'' +
                '}';
    }
}

 

同步读取 ( 数据量大的时候,不推荐使用,内存消耗比较大  )

    // 简单读取 (同步读取)
    public static void simpleRead() {

        // 读取 excel 表格的路径
        String readPath = "C:\\Users\\oukele\\Desktop\\模拟数据.xlsx";

        try {
            // sheetNo --> 读取哪一个 表单
            // headLineMun --> 从哪一行开始读取( 不包括定义的这一行,比如 headLineMun为2 ,那么取出来的数据是从 第三行的数据开始读取 )
            // clazz --> 将读取的数据,转化成对应的实体,需要 extends BaseRowModel
            Sheet sheet = new Sheet(1, 1, ExcelMode.class);

            // 这里 取出来的是 ExcelModel实体 的集合
            List<Object> readList = EasyExcelFactory.read(new FileInputStream(readPath), sheet);
            // 存 ExcelMode 实体的 集合
            List<ExcelMode> list = new ArrayList<ExcelMode>();
            for (Object obj : readList) {
                list.add((ExcelMode) obj);
            }

            // 取出数据
            StringBuilder str = new StringBuilder();
            str.append("{");
            String link = "";
            for (ExcelMode mode : list) {
                str.append(link).append("\""+mode.getColumn1()+"\":").append("\""+mode.getColumn2()+"\"");
                link= ",";
            }
            str.append("};");
            System.out.println(str);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }


    }

 

异步读取

新建一个  ExcelModelListener 监听类出来,并且 继承 AnalysisEventListener 类

package com.zh.oukele.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.zh.oukele.model.ExcelMode;

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

/***
 *  监听器
 */
public class ExcelModelListener extends AnalysisEventListener<ExcelMode> {

    /**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 5;
    List<ExcelMode> list = new ArrayList<ExcelMode>();
    private static int count = 1;
    @Override
    public void invoke(ExcelMode data, AnalysisContext context) {
        System.out.println("解析到一条数据:{ "+ data.toString() +" }");
        list.add(data);
        count ++;
        if (list.size() >= BATCH_COUNT) {
            saveData( count );
            list.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData( count );
        System.out.println("所有数据解析完成!");
        System.out.println(" count :" + count);
    }

    /**
     * 加上存储数据库
     */
    private void saveData(int count) {
        System.out.println("{ "+ count +" }条数据,开始存储数据库!" + list.size());
        System.out.println("存储数据库成功!");
    }

}

进行读取

 

    // 异步读取
    public static void simpleRead1(){

        // 读取 excel 表格的路径
        String readPath = "C:\\Users\\oukele\\Desktop\\模拟数据.xlsx";

        try {
            Sheet sheet = new Sheet(1,1,ExcelMode.class);
            EasyExcelFactory.readBySax(new FileInputStream(readPath),sheet,new ExcelModelListener());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

读取出来的日期 是 double 类型,转换一下

                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                    Date date = HSSFDateUtil.getJavaDate(Double.parseDouble(mode.getColumn2()));
                    String time = sdf.format(date);
                    System.out.println(time);
<think>好的,我现在需要帮助用户解决如何使用EasyExcel读取Excel文件中的原始数据。首先,我得回忆一下EasyExcel的基本使用方法,以及用户提到的引用内容。 根据引用[4],EasyExcel采用SAX解析,低内存占用,适合大文件处理。用户需要获取原始数据,可能包括单元格值、格式或公式。但EasyExcel默认是处理数据的,可能不会直接保留所有原始信息,比如公式可能需要特别处理。 用户的问题是如何用EasyExcel获取原始数据。首先,我需要确定“原始数据”指的是什么。如果是单元格的值,包括字符串、数字等,那么常规的读取方式就可以。但如果需要公式计算前的值或者单元格的样式,可能需要更深入的配置。 引用[4]还提到监听器模式,用于分页读取大数据量。所以,使用读取监听器是关键。常规做法是继承AnalysisEventListener,重写invoke方法处理每一行数据。但是要获取原始数据,可能需要访问单元格本身的信息,而不仅仅是解析后的对象。 查看EasyExcel的文档(引用[2]和[3]),读取时可以指定自定义的ReadListener,并通过AnalysisContext获取当前行的原始数据。例如,在invoke方法中,可以通过context.readRowHolder().getCellMap()来获取单元格的原始值,这可能包括字符串形式的数字或公式结果。 另外,用户可能需要处理不同的数据类型,比如日期或数字格式。EasyExcel默认会进行类型转换,但若需要原始字符串,可能需要禁用转换器,或者在读取时保留字符串形式。例如,在读取时添加@ExcelProperty注解,使用converter指定字符串转换器。 还需要考虑Excel的版本,.xls和.xlsx的处理是否一致。根据引用[4],EasyExcel支持这两种格式,所以应该没问题。 可能用户会遇到合并单元格的情况,这时候需要判断单元格是否为合并区域,但EasyExcel的监听器可能无法直接处理,需要额外的逻辑或者在读取后处理数据。 总结步骤应该是:创建实体类(可选)、创建监听器、构建读取器并执行读取。如果不需要映射到对象,可以直接读取为Map或使用无模型模式,这样每一行数据以Map形式呈现,键为列索引或标题。 另外,引用[5]提到接口封装和灵活性,可能建议用户将读取逻辑封装成可复用的组件,方便后续扩展。 最后,需要验证示例代码的正确性,确保使用正确的方法和类,比如ExcelReaderBuilder、sheet方法、headRowNumber设置等。同时,提醒用户注意异常处理和资源释放,比如在finally块中关闭流。</think>以下是使用EasyExcel获取Excel原始数据的完整解决方案: ### 一、基础读取方式 通过监听器模式逐行读取原始数据,核心方法如下: ```java public class RawDataListener extends AnalysisEventListener<Map<Integer, String>> { private List<Map<Integer, String>> rawData = new ArrayList<>(); @Override public void invoke(Map<Integer, String> rowData, AnalysisContext context) { // 获取单元格原始字符串值 Map<Integer, CellData> cellMap = context.readRowHolder().getCellMap(); Map<Integer, String> row = new HashMap<>(); cellMap.forEach((colIndex, cell) -> { row.put(colIndex, cell.getStringValue()); // 原始字符串值 }); rawData.add(row); } public List<Map<Integer, String>> getRawData() { return rawData; } } ``` ### 二、关键配置步骤 1. **设置不自动转换类型**: ```java ReadSheet readSheet = EasyExcel.readSheet(0) .headRowNumber(0) // 从第0行开始读取 .build(); EasyExcel.read(inputStream, new RawDataListener()) .autoTrim(false) // 保留原始空格 .autoCloseStream(true) .read(readSheet); ``` 2. **获取元数据**: ```java // 获取总行数(含空行) context.readSheetHolder().getTotal(); // 获取单元格样式 cell.getCellStyle().getDataFormatString(); ``` ### 三、完整示例代码 ```java public List<Map<Integer, String>> readRawData(String filePath) { try (InputStream in = new FileInputStream(filePath)) { RawDataListener listener = new RawDataListener(); ExcelReader excelReader = EasyExcel.read(in, listener) .autoTrim(false) .ignoreEmptyRow(false) // 包含空行 .build(); ReadSheet readSheet = EasyExcel.readSheet(0) .headRowNumber(0) .build(); excelReader.read(readSheet); return listener.getRawData(); } } ``` ### 四、注意事项 1. 公式单元格需特殊处理: ```java if (cell.getType() == CellType.FORMULA) { String formula = cell.getFormulaValue(); // 获取公式 String cachedValue = cell.getStringValue(); // 获取缓存值 } ``` 2. 日期数据会返回Excel内部数值格式,需自行转换[^4] 3. 合并单元格会重复出现在多个行记录中
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值