“没有做过附件处理的程序员不算一个合格的滴滴司机,附件中的隐形坑90%开发者不知道”
01
—
背景
话说,在日常的开发中,Excel 批量导入ID、编码、门店号是非常高频的操作。最近业务同学在使用一个后台系统的导入功能时系统报了一个错误提示:

是不是平时群里回复太积极了,上来就圈我,又不是我做的
。根据提示找代码看了下:

逻辑还是比较简单:Excle解析出来的数据如果不满足业务规则,错误变量加1,当不等于0的时候说明某列不合法就会提示,于是先反弹回去:为啥子每天这么多人用,别人没反应,就你有,让对方检查数据格式,我悄悄的研究了一把。
02
—
拉扯
其实做开发的大都是心软的人,特别是女孩子反应的问题
,在好奇心的加持下研究了一把,技术栈也很标准:
SpringBoot Apache POI( org.apache.poi.ss.usermodel.Workbook)
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.15</version></dependency><dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3</artifactId><version>1.9.0</version></dependency>
读取 Excel (模拟一些数据)→ 转为 String → 校验入库 



正当我准备斩钉截铁回复时,对方说用AI分析了下,果然不出我所料,AI说没有任何问题
,是纯数字:

就她会AI?我的豆包呢?结果叛变了,这边文章的基因就来自这里

——替你们试过了,不行的

03
—
复现
上面都是猜测,好在代码可以跑起来,实测了一下发现其中一个变了:

。是不是想知道为啥?观察发现:末尾带 0 的数字,被转成科学计数法,难道是巧合?在出问题的数字前后我又随便造几个假数据,重启后确认末尾0就有这个问题。

04
—
WHY
以前查百度,现在问AI方便多了(百度要加油啊
),结论如下:
这是 Excel 和 Java 数值解析的共同特性,核心原因是有效数字位数阈值:
Excel 的「常规」格式,对于有效数字超过 6 位的整数,会自动用科学计数法显示 / 存储;
末尾带 0 的 8 位数字,刚好卡在这个阈值上:
32051060:8 位数字,末尾 1 个 0,有效数字是 7 位,超过 6 位,Excel 会自动转为科学计数法3.205106E+7,Java 框架读取后,转成 String 就会保留这个科学计数法格式;32051061:8 位数字,末尾无 0,有效数字是 8 位,Excel「常规」格式下会完整显示,Java 框架读取后也能拿到完整的数字字符串。String,也拦不住这个「先转数值,再转字符串」的过程,科学计数法就是在这个环节被带进来的。查询源码发现果然如此:



还是好奇,既然前面提到Excel超过6位才有这个问题,我又造了几个数字试了下:
Case 1:3205900(7 位数字,末尾 2 个 0)
数值大小:3205900,7 位整数,有效数字 7 位,超过 6 位临界值 读取结果: 3.2059E6(科学计数法)正则校验结果:❌ 失败(包含小数点、字母 E) 为什么会触发?7 位数字,有效数字超过 6 位,且末尾带 0,是 10 的整数次幂的倍数
Case 2:32051060(8 位数字,末尾 1 个 0)
数值大小:32051060,8 位整数,有效数字 7 位,超过 6 位临界值 读取结果: 3.205106E7(科学计数法)正则校验结果:❌ 失败 为什么会触发?同上
Case 3:32054928(8 位数字,末尾无 0)
数值大小:32054928,8 位整数,有效数字 8 位,超过 6 位临界值 读取结果: 32054928(完整纯数字字符串)正则校验结果:✅ 完全通过 为什么不会触发?虽然有效数字超过 6 位,但末尾不带 0,不是 10 的整数次幂的倍数
Case 4:123456(6 位数字,末尾无 0)、123000(6 位数字,末尾 3 个 0)
读取结果:均为完整的纯数字字符串,无科学计数法 正则校验结果:✅ 全部通过 原因:6 位及以内数字,有效数字未超过 6 位的临界阈值,Excel 和 Java 都不会触发科学计数法的优化,天然安全。 
05
—
解决方案
import org.apache.poi.ss.usermodel.DataFormatter;import org.apache.poi.ss.usermodel.Cell;// 全局单例private static final DataFormatter DATA_FORMATTER = new DataFormatter();// 正确读取方式String cellValue = DATA_FORMATTER.formatCellValue(cell).trim();

32051060,数值上没有任何问题。但它的字符串形式里,包含了 3 个正则不允许的字符:小数点./字母E/加号+,「数值意义上的数字」和「字符串形式的纯数字」是两个完全不同的概念。
- Apache POI 官方 DataFormatter说明:
https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/DataFormatter.html
Java 官方 Double.toString () 科学计数法触发规则:
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Double.html#toString(double)
夜雨聆风