在使用 EasyExcel 读取 Excel 时,我们经常会遇到这样一个问题:
同一个单元格,Excel 界面显示 119178409,但在公式栏里显示的原始值却是 119178408.985065。

而通过 EasyExcel 读取后,拿到的值始终是 119178409,即 Excel 的“显示值”,而不是底层存储的原始值。
这在财务、对账、数据精度要求较高的场景里,往往会造成严重的数据误差。
Excel 单元格内容:
119178409119178408.985065使用 EasyExcel 默认读取方式:
EasyExcel.read(fileBytes) .registerReadListener(new ReadListener<Map<Integer, String>>() { @Override public void invoke(Map<Integer, String> data, AnalysisContext context) { System.out.println(data); } @Override public void doAfterAllAnalysed(AnalysisContext context) {} }).sheet().doRead(); 输出结果:
{0=119178409} 可以看到,原始的 119178408.985065 被四舍五入成了 119178409。
EasyExcel 的默认行为是:
Map<Integer, String>,使用内置的 StringConverter。StringConverter 内部依赖 Apache POI 的 DataFormatter。DataFormatter 返回的就是 Excel UI 显示值,而不是单元格底层的存储值。所以,只要你用 Map<Integer, String> 或者 Java Bean 的 String 字段接收,就一定会丢失原始精度。
Map<Integer, CellData>(推荐)直接拿 CellData,通过 getNumberValue() 获取 Excel 的原始值:
EasyExcel.read(fileBytes) .registerReadListener(new ReadListener<Map<Integer, CellData>>() { @Override public void invoke(Map<Integer, CellData> data, AnalysisContext context) { for (Map.Entry<Integer, CellData> entry : data.entrySet()) { CellData cellData = entry.getValue(); if (cellData.getType() == CellDataTypeEnum.NUMBER) { System.out.println("原始值 = " + cellData.getNumberValue().toPlainString()); } } } @Override public void doAfterAllAnalysed(AnalysisContext context) {} }).sheet().doRead(); 输出结果:
原始值 = 119178408.985065 如果你必须用 Map<Integer, String>,可以自定义一个 RawNumberStringConverter:
public class RawNumberStringConverter implements Converter<String> { @Override public Class<?> supportJavaTypeKey() { return String.class; } @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.NUMBER; } @Override public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue().toPlainString(); } } 注册时一定要放在前面,覆盖默认的:
EasyExcel.read(fileBytes) .registerConverter(new RawNumberStringConverter()) .registerReadListener(new ReadListener<Map<Integer, String>>() { @Override public void invoke(Map<Integer, String> data, AnalysisContext context) { System.out.println(data); } @Override public void doAfterAllAnalysed(AnalysisContext context) {} }).sheet().doRead(); 这样 data 中拿到的就是 119178408.985065。
Map<Integer, CellData>,直接取 getNumberValue();Converter 覆盖默认的 StringConverter。⚠️ 经验教训:EasyExcel 在默认场景下非常方便,但在高精度数值处理场景里,一定要检查它是否返回了 原始值,否则可能踩坑。