You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring FlatFile读取CSV最后一行空值引发空指针异常的解决方法

解决CSV读取末尾空行引发NullPointerException的问题

我来帮你搞定这个CSV读取时最后空行引发NPE的问题~

首先分析下问题根源:你遇到的情况大概率是循环逻辑的判断时机不对,或者FlatFileItemReader没有配置过滤空行,导致空行被解析成null的ProductService对象,进而在处理时抛出NPE。你虽然加了while (newPs != null)的判断,但如果判断位置不对,还是会踩坑。

下面给你几个可行的解决方案,按优先级排序:

1. 修正循环读取的逻辑(最直接)

很多时候问题出在循环的写法上,正确的做法是先读取,再判断是否为null,只有非null才处理。比如把读取操作直接放在while的条件里:

public void readPsFile(MultipartFile batchFile) throws Exception {
    FlatFileItemReader<ProductService> reader = new FlatFileItemReader<>();
    // 这里省略你的tokenizer、lineMapper配置...
    
    reader.open(new ExecutionContext());
    ProductService newPs;
    
    // 核心:先读取,判断非null再进入循环处理
    while ((newPs = reader.read()) != null) {
        // 在这里处理打印所有值的逻辑
        System.out.println("读取到的数据:" + newPs);
    }
    
    reader.close();
}

这种写法能确保只有当reader.read()返回非null的对象时,才会执行处理逻辑,从根源上避免处理null对象。

2. 配置FlatFileItemReader过滤空行(更优雅)

如果你的CSV文件末尾经常有空行,可以直接给Reader配置一个空行过滤器,提前把空行过滤掉,不用在循环里额外判断。Spring Batch提供了内置的EmptyRecordFilter,专门用来过滤空行:

public void readPsFile(MultipartFile batchFile) throws Exception {
    FlatFileItemReader<ProductService> reader = new FlatFileItemReader<>();
    
    DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
    tokenizer.setNames("你的列名1", "你的列名2"); // 替换成实际CSV列名
    tokenizer.setStrict(false); // 允许列数不匹配,避免空行解析报错
    
    BeanWrapperFieldSetMapper<ProductService> mapper = new BeanWrapperFieldSetMapper<>();
    mapper.setTargetType(ProductService.class);
    
    DefaultLineMapper<ProductService> lineMapper = new DefaultLineMapper<>();
    lineMapper.setLineTokenizer(tokenizer);
    lineMapper.setFieldSetMapper(mapper);
    
    reader.setLineMapper(lineMapper);
    reader.setResource(new ByteArrayResource(batchFile.getBytes()));
    // 关键:添加空行过滤器
    reader.setFilter(new EmptyRecordFilter());
    
    reader.open(new ExecutionContext());
    ProductService newPs;
    while ((newPs = reader.read()) != null) {
        // 处理逻辑
        System.out.println(newPs);
    }
    reader.close();
}

这里的EmptyRecordFilter会自动跳过所有空行(包括只含空格的行),这些空行根本不会被解析成ProductService对象,自然不会出现null的情况。另外设置tokenizer.setStrict(false)是为了避免空行解析时因为列数不匹配抛出异常。

3. 自定义过滤器处理特殊空行(灵活)

如果你的空行不是完全空白,而是有空格或者其他特殊字符,可以自定义一个过滤器:

reader.setFilter(new RecordFilter() {
    @Override
    public boolean accept(String line) {
        // 自定义判断逻辑:比如去掉首尾空格后不为空才保留
        return StringUtils.isNotBlank(line.trim());
    }
});

这样可以更灵活地过滤掉不符合要求的行。


内容的提问来源于stack exchange,提问作者Jacel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:56:54