【问题标题】:Read a csv file using FlatFileItemReader, throwing an exception when encountering an empty column使用FlatFileItemReader读取csv文件,遇到空列抛出异常
【发布时间】: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,如何配置?

【问题讨论】:

标签: java spring-boot csv spring-batch


【解决方案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】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-16
      相关资源
      最近更新 更多