使用FlatFileItemReader读取csv文件,遇到空列抛出异常

Posted

技术标签:

【中文标题】使用FlatFileItemReader读取csv文件,遇到空列抛出异常【英文标题】:Read a csv file using FlatFileItemReader, throwing an exception when encountering an empty column 【发布时间】:2020-01-28 22:16:38 【问题描述】:

使用 FlatFileItemReader 读取 csv 文件时,列映射类型为 Int,但该列在 csv 文件中为空(例如:6321517,Jack, 1,,。最后两列为空)。 解析文件时抛出异常(java.lang.NumberFormatException: Unparseable number

csv

CUSTR_NBR,SUR_NAME,CHECK_FLAG,RESN_CODE
6321517,Jack,1,,

首先解析第一行数据(CUSTR_NBR,SUR_NAME,CHECK_FLAG,RESN_CODE),所以我设置.SetLinesToSkip(1)。但是,如果解析为空值,则无法正常执行相应的“CHECK_FLAG”和“RESN_CODE”。相信有对应的配置项。看了springbatch的文档,没有找到相关的配置项。

csvItemReader

    @Bean
    @StepScope
    public FlatFileItemReader<InfoDTO> csvItemReader() 
        FlatFileItemReader<InfoDTO> csvItemReader = new FlatFileItemReader<>();
        csvItemReader.setResource(new ClassPathResource("data/charge-off.csv"));
        csvItemReader.setLinesToSkip(1);

        DelimitedLineTokenizer tokenizer=new DelimitedLineTokenizer();
        String[] tokens = new String[]"CUSTR_NBR","SUR_NAME","CHECK_FLAG","RESN_CODE","EMPNO";
        tokenizer.setNames(tokens);
        DefaultLineMapper<InfoDTO> lineMapper=new DefaultLineMapper<InfoDTO>();
        lineMapper.setLineTokenizer(tokenizer);
        lineMapper.setFieldSetMapper(new InfoFileMapper());
        lineMapper.afterPropertiesSet();
        csvItemReader.setLineMapper(lineMapper);

        return csvItemReader;
    

映射器

    public class InfoFileMapper implements FieldSetMapper<ChargeOffBatchDTO> 
        @Override
        public InfoDTO mapFieldSet(FieldSet fieldSet) throws BindException 

            if(fieldSet == null)
                return null;
            

            return new InfoDTO(
                fieldSet.readString("CUSTR_NBR"),
                fieldSet.readString("SUR_NAME"),
                fieldSet.readString("CHECK_FLAG"),
                fieldSet.readInt("RESN_CODE"),
                fieldSet.readInt("EMPNO")
            );
        
    

我需要将空列映射为0,如何配置?

【问题讨论】:

spring-batch read in null int values的可能重复 【参考方案1】:

我没有使用过 Spring Batch,但是查看 FieldSet Interface specification,似乎有一些替代方法可以实现你想要的。

Spring Batch reference 确实提到了一些容错性,特别是在值不存在时抛出异常。要禁用此功能,您需要将 strict 设置为 false

tokenizer.setStrict(false);

否则您可以简单地尝试一些老式的替代方法,例如不要尝试将值直接读入int,只需将其读入字符串,然后在将其转换为int之前验证该字符串

String empNo = fieldSet.readString("EMPNO");
if ((empNo == null) || (empNo.equals(""))) 
  empNo = "0";

int i = Integer.valueOf(empNo);

如果字段不为空且不是字符串,您可能仍会得到java.lang.NumberFormatException,所以我个人只会通过处理异常来解决问题:

int myEmp = 0;
try 
  myEmp = fieldSet.readInt("EMPNO");
 catch (NumberFormatException nfe) 
  myEmp = 0;

它可能不是那么雄辩,但它会起作用并达到目的。

【讨论】:

【参考方案2】:

您可以创建自己的线映射器实现并检查它是否为空的子字符串并将其替换为零并将该线向前传递。

【讨论】:

以上是关于使用FlatFileItemReader读取csv文件,遇到空列抛出异常的主要内容,如果未能解决你的问题,请参考以下文章

MultiResourceItemReader 未按预期工作

Spring Batch - 从 S3 读取多个文件

Spring Batch 项目读取监听器

gh读取csv文件

Spring批处理在拒绝文件中保存跳过的读取器行

python3.4读取.csv