Java使用Excel的问题:自动跳过空字段中文加拼音和时间处理错误的解决方法
Posted 纵横千里,捭阖四方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java使用Excel的问题:自动跳过空字段中文加拼音和时间处理错误的解决方法相关的知识,希望对你有一定的参考价值。
在Java中解析Excel是很多管理类系统的重要功能, 目前主要有阿里的easyExcel和HSSF两种开源工具,如何使用网上有大量的例子,不再赘述,我们这里看三个我亲身经历的问题:
-
自动跳过空字段
-
中文内容自动给加了拼音
-
时间处理错误。
本文首先分析故障现象或者原因,之后给出解决方案。
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解析时间会出现如下情况:
-
如果日期是Date类型,则直接抛异常。
-
如果时间是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类型拿到所有数据,我们自己转换。
以上是关于Java使用Excel的问题:自动跳过空字段中文加拼音和时间处理错误的解决方法的主要内容,如果未能解决你的问题,请参考以下文章