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

如何通过Spring Batch的MultiResourceItemReader统计单个文件记录数?

Spring Batch 统计单个文件记录数实现方案

方案一:自定义跟踪型ItemReader包装MultiResourceItemReader

MultiResourceItemReader会逐个加载资源文件,我们可以包装它来跟踪当前文件的记录数,在文件切换或读取结束时写入主表:

  1. 实现ItemStreamReader接口,内部持有MultiResourceItemReader和统计相关变量:
public class TrackingItemReader<T> implements ItemStreamReader<T> {
    private MultiResourceItemReader<T> delegate;
    private int currentFileRecordCount;
    private Resource currentResource;
    private MainDataWriter mainDataWriter; // 注入主数据表写入器

    @Override
    public T read() throws Exception {
        T item = delegate.read();
        if (item != null) {
            currentFileRecordCount++;
        } else {
            // 当前文件读取完毕,写入统计
            writeCurrentFileStats();
            resetTrackingState();
        }
        return item;
    }

    @Override
    public void open(ExecutionContext executionContext) throws ItemStreamException {
        delegate.open(executionContext);
        currentResource = delegate.getCurrentResource();
    }

    @Override
    public void update(ExecutionContext executionContext) throws ItemStreamException {
        delegate.update(executionContext);
        Resource newResource = delegate.getCurrentResource();
        // 检测到文件切换,先写入上一个文件的统计
        if (!Objects.equals(currentResource, newResource)) {
            writeCurrentFileStats();
            currentResource = newResource;
            currentFileRecordCount = 0;
        }
    }

    @Override
    public void close() throws ItemStreamException {
        delegate.close();
        // 处理最后一个文件的统计
        writeCurrentFileStats();
    }

    private void writeCurrentFileStats() {
        if (currentResource != null) {
            mainDataWriter.write(Collections.singletonList(
                new MainData(currentResource.getFilename(), currentFileRecordCount)
            ));
        }
    }

    private void resetTrackingState() {
        currentFileRecordCount = 0;
        currentResource = null;
    }

    // getter/setter 注入delegate和mainDataWriter
}
  1. 配置Step时,用这个自定义Reader替代直接使用MultiResourceItemReader,把原MultiResourceItemReader作为delegate注入即可。

方案二:结合ItemReadListener跟踪文件切换

利用MultiResourceItemReader的getCurrentResource()方法,在监听器中实时跟踪当前文件,切换时完成上一个文件的统计:

  1. 自定义监听器实现ItemReadListener和ItemStream:
public class FileRecordCountListener<T> implements ItemReadListener<T>, ItemStream {
    private int currentCount;
    private Resource currentFile;
    private MultiResourceItemReader<T> multiResourceReader;
    private MainDataWriter mainDataWriter;

    @Override
    public void afterRead(T item) {
        Resource activeResource = multiResourceReader.getCurrentResource();
        if (!Objects.equals(currentFile, activeResource)) {
            // 切换文件,先写入上一个文件的统计
            if (currentFile != null) {
                writeStats(currentFile, currentCount);
            }
            currentFile = activeResource;
            currentCount = 1;
        } else {
            currentCount++;
        }
    }

    @Override
    public void open(ExecutionContext executionContext) {
        currentCount = 0;
        currentFile = null;
    }

    @Override
    public void close() {
        // 处理最后一个文件
        if (currentFile != null) {
            writeStats(currentFile, currentCount);
        }
    }

    private void writeStats(Resource file, int count) {
        mainDataWriter.write(Collections.singletonList(
            new MainData(file.getFilename(), count)
        ));
    }

    // getter/setter 注入multiResourceReader和mainDataWriter
}
  1. 将该监听器注册到Step中,确保注入MultiResourceItemReader实例。

方案三:给单个文件的Reader添加统计逻辑

MultiResourceItemReader内部用delegate Reader处理单个文件,我们可以给每个文件的Reader包装统计逻辑,在文件读取结束时写入主表:

  1. 实现带统计功能的Reader:
public class CountingItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> {
    private ItemReader<T> delegate;
    private int recordCount;
    private Resource currentFile;
    private MainDataWriter mainDataWriter;

    @Override
    protected T doRead() throws Exception {
        T item = delegate.read();
        if (item != null) {
            recordCount++;
        }
        return item;
    }

    @Override
    protected void doOpen() throws Exception {
        delegate.open(getExecutionContext());
        recordCount = 0;
    }

    @Override
    protected void doClose() throws Exception {
        delegate.close();
        // 文件读取完毕,写入统计
        if (currentFile != null) {
            mainDataWriter.write(Collections.singletonList(
                new MainData(currentFile.getFilename(), recordCount)
            ));
        }
    }

    // getter/setter 注入delegate、currentFile、mainDataWriter
}
  1. 配置MultiResourceItemReader时,设置resourceAwareItemReaderDelegate为这个CountingItemReader,让它自动给每个加载的资源设置到currentFile属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 16:37:08