EasyExcel读取某些07版excel出现小数点精度问题

在使用EasyExcel读取07版Excel时遇到小数精度问题,如156.23解析为156.22999999999999。通过分析源码发现,DoubleNumberConverter直接获取BigDecimal的NumberValue,导致精度丢失。而StringNumberConverter使用格式化处理,能正确显示156.23。解决办法是在解析后对double字段使用BigDecimal进行四舍五入处理,确保与软件显示一致。对于Excel为何显示与实际存储不同,可能涉及Office的内部存储规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用easyexcel时碰到一个这样的问题,读取某个office编辑过的07版excel时,出现了小数点精度问题。例如,156.23这个值,使用easyexcel解析后得到的Double对象就变成了156.22999999999999。

我尝试去查看了excel解压后的文件,发现这条数据在xml里存储的值就是156.22999999999999。

奇怪的是,当我在把实体类里把Double的字段修改成String类型后,读出来的数据就是期望的156.23。

查看easyexcel源码,其实easyexcel解析excel单元格的时候,会根据单元格格式选择不同的converter。在本例中,由于是数字类型单元格解析成Double类型字段,调用的就是DoubleNumberConverter。这个Converter是这样的:

 

public class DoubleNumberConverter implements Converter<Double> {

    @Override
    public Class supportJavaTypeKey() {
        return Double.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.NUMBER;
    }

    @Override
    public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) {
        return cellData.getNumberValue().doubleValue();
    }

    @Override
    public CellData convertToExcelData(Doubl
### 解决 EasyExcel 数据导入中的数据类型转换 为了确保在使用 EasyExcel 进行数据导入时能够正确处理不同类型的数据,可以采取多种策略来实现有效的数据类型转换。 #### 使用自定义转换器解决 long 类型数据精度丢失问题 对于 `long` 类型的数据,在读取过程中可能会因为默认解析方式而导致精度损失。为此可以通过创建自定义转换器的方式解决问题[^1]: ```java public class LongConverter implements Converter<Long> { @Override public Class<?> supportJavaTypeKey() { return Long.class; } @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.NUMBER; } /** * 将字符串形式的数值转化为Long对象 */ @Override public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { String value = (String)cellData.getStringValue(); return Long.parseLong(value); } } ``` 此代码片段展示了如何构建一个专门用于处理 `long` 型字段的转换逻辑,从而避免了潜在的小数点截断风险并保持原始数据完整性。 #### 处理日期格式的数据 当面对来自 Excel 文件内的日期信息时,则需特别注意其存储模式以及目标 Java 实体类属性之间的映射关系。通常情况下建议采用如下所示的方法来进行适配操作[^3]: ```java @DateTimeFormat(pattern="yyyy-MM-dd") // 或者其他所需的时间样式 private Date dateField; // 对应于实体类成员变量上的注解配置 @Data public static class DataModel{ private String name; @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") private LocalDateTime dateTime; } ``` 上述例子说明了怎样利用 Spring 提供的 `@DateTimeFormat` 注释标记配合特定时间表达式完成自动化的日期解析工作;当然也可以根据实际需求调整 pattern 参数值以匹配不同的输入源格式。 #### 配置全局监听器或局部处理器 除了针对单个字段设置特殊规则外,还可以考虑在整个文档级别引入统一管理机制——即通过继承 `AnalysisEventListener<T>` 接口定制专属事件响应程序,并将其传递给 `ExcelReader.Builder` 构造函数作为参数之一参与后续流程控制[^4]: ```java new ExcelReader(inputStream, ExcelTypeEnum.XLSX, new AnalysisEventListener<DataModel>() {/*...*/}) ``` 这种方式允许开发者更加灵活地介入到每一行记录被加载后的即时状态评估环节当中,进而实施更为复杂精细的操作比如异常捕获、业务校验等附加功能模块集成进来。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值