Java使用Excel的问题:自动跳过空字段、中文加拼音和时间处理错误的解决方法

在Java中解析Excel是很多管理类系统的重要功能, 目前主要有阿里的easyExcel和HSSF两种开源工具,如何使用网上有大量的例子,不再赘述,我们这里看三个我亲身经历的问题:

  1. 自动跳过空字段

  2. 中文内容自动给加了拼音

  3. 时间处理错误。

本文首先分析故障现象或者原因,之后给出解决方案。

1.自动跳过空字段

有些场景下上传的excle文件里有些选项是可选的,用户自然可以不填,但是在使用时会遇到问题。

例如如下的文件:

用户是否签到和是否允许使用pad都是可选的,用户可以根据实际需要填或者不填。但是我们在java 中使用XLSX提供的方法自动读取Excel,如下:

 String fileName = "/Users/liuqingchao/Downloads/five_2.xlsx";

List<List<String>> lists = ExcelUtils.getXLSXDataOfFirstSheet(new FileInputStream(fileName));

结果会出现这样子:

可以看到,debug中很多行是空的,其中序号2、3、4对应的行元素都少了,其中序号2对应的是将文件中的空位置直接跳过了,这是无法接受的,因为后续对应关系都无法确定了。

测试发现,使用XSSF和早期版本的easyExcel都存在该问题。其底层都是基于迭代器方式读的,直接修改其源码不现实,但是可以自己来解析文件,详细实现见asyn-task的getExcelFileFixedZh()方法。

但是使用该方法会导致解析时间时出错。详见下一小节。

2.时间解析错误

我们知道正常的时间格式是”2022-10-31 16:09:13“,但是如果将其放在一个Excel格子里,用户在操作的时候,可能会将其写错,最明显的就是日期和时间之间的空格,如果是中文的空格,用户无法发现的,但是后续处理就会有问题,所以最好将其分开,日期和时间分别用一个格子,例如篇头给出的样子。

但是解析的时候仍然出问题,我们使用如下的代码来解析:

String fileName = "/Users/liuqingchao/Downloads/five_2.xlsx";
List<List<String>> lists= ExcelUtilsFixedZh.getExcelDataRowsInFirstSheet(new FileInputStream(fileName));
        System.out.println(lists);

可以看到日期解析没有问题,但是时间格子对应的全错了:

 

查阅之后发现,如果格子里存的是时间,Excel会自动进行类型转换, 没有日期就从1900年1月1日开始算,此时会出现两种情况,一种是直接将时间转换成”1900.1.1 19:00:00“,另一种是将时间倒退一天给变成”1899.1.1 19:00:00“,而后者转成时间戳就是我们看到的-2209035600000。前者在阿里easy Excel中出现过。

很明显,这都不是我们想要的。

而且,即使此时将List定义为List<List<String>>也无法阻止Excel自动转换时间。

3.中文信息后面带了拼音

该问题是于波发现的,偶尔出现,本人没能复现出来,现象就是中文信息后面自动给加了拼音, 例如本来存的是”否“,但是实际读到的是”否fou“。

4.解决方法

针对上述几个问题,目前发现比较好的方式是:使用easyExcel版本3。并定义一个与一行记录相对应的类。读取的时候,将类对象设置进去,这样可以解决上面提到的三个问题。

具体操作方法见:truman-lecture里AbstractExcelUploadExecutor下的

 List<BatchAddEpisodesExcelVO> records;
        try {
            records = AsynTaskFileUtils.getEasyExcelFileRecord(this.httpClient, innerHost, getParams().getResourceId(), BatchAddEpisodesExcelVO.class);
        }

这里的BatchAddEpisodesExcelVO就是与Excel文件完全对应的类对象。获得记录的核心为:

    public static <T> List<T> getEasyExcelFileRecord(HttpClient httpClient, String host, String resourceId, Class clazz) {

.....
            EasyExcel.read(connection.getInputStream(), clazz, new PageReadListener<T>(dataList -> {
                for (T demoData : dataList) {
                    list.add(demoData);
                }
            })).sheet().doReadSync();//同步方式
            return list;
.....
    }

此时虽然用了回调,但是将其设置为同步模式就可以保证获得全部记录之后才返回。

注意事项

另外注意一点,我们定义BatchAddEpisodesExcelVO这种与excle对应的对象的时候,最好将所有的属性,特别是日期相关务必用String类型,这样可以避免Excel给我们做数据转换。否则使用easyExcle解析时间会出现如下情况:

  1. 如果日期是Date类型,则直接抛异常。

  2. 如果时间是Date类型,则时间仍然是错的。

例如,我们还是使用上的文件,定义一个简单类:

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
    private String lectureId;
    private Date beginDate;
    private String beginTime;
    private String yunXu;
    private String locale;
}

然后执行,此时直接抛异常:

com.alibaba.excel.exception.ExcelDataConvertException: Convert data com.alibaba.excel.metadata.data.ReadCellData@4f7479f3 to class java.util.Date error 

如果我们将上面的beginTime的类型改成Date,则时间错误:

 结论:不要让excle给我们做转换,都先用String类型拿到所有数据,我们自己转换。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵横千里,捭阖四方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值