Spring Batch如何读取多个同结构CSV文件?当前使用FlatFileItemReader
读取多个同结构CSV文件的Spring Batch解决方案
嘿,你说得没错,默认的FlatFileItemReader确实只能处理单个文件~不过Spring Batch专门为这种多文件场景提供了适配方案,下面给你两个实用的解决思路:
方案一:使用MultiResourceItemReader(最推荐)
这是Spring Batch官方针对多文件读取设计的组件,它可以把多个同结构文件资源交给底层的FlatFileItemReader逐个处理,完美匹配你的需求。
你可以把原来的FlatFileItemReader作为委托阅读器(delegate),再用MultiResourceItemReader包装它,示例代码如下:
@Bean public FlatFileItemReader<HotelCSVDto> hotelCsvDelegateReader() { FlatFileItemReader<HotelCSVDto> reader = new FlatFileItemReader<>(); // 这里不再设置单个资源,交给MultiResourceItemReader统一处理 reader.setLineMapper(new DefaultLineMapper<HotelCSVDto>() {{ setLineTokenizer(new DelimitedLineTokenizer() {{ // 配置你的CSV分隔符、列名等规则 setDelimiter(","); setNames(new String[]{"id", "name", "address", ...}); }}); setFieldSetMapper(new BeanWrapperFieldSetMapper<HotelCSVDto>() {{ setTargetType(HotelCSVDto.class); }}); }}); // 保留你原来的RecordSeparatorPolicy配置 reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy(...)); return reader; } @Bean public MultiResourceItemReader<HotelCSVDto> multiHotelReader() throws IOException { MultiResourceItemReader<HotelCSVDto> reader = new MultiResourceItemReader<>(); // 用路径匹配器批量获取BASE_PATH下符合规则的CSV文件 Resource[] resources = new PathMatchingResourcePatternResolver() .getResources("classpath:" + BASE_PATH + "Hotels-*.csv"); reader.setResources(resources); // 设置委托阅读器,由它处理单个文件的内容解析 reader.setDelegate(hotelCsvDelegateReader()); // 可选:设置为false的话,即使没找到匹配文件也不会直接报错 reader.setStrict(false); return reader; }
关键说明:
MultiResourceItemReader会遍历你指定的所有文件,逐个交给FlatFileItemReader解析,输出的HotelCSVDto数据和单个文件读取时完全一致- 可以通过路径匹配规则(比如
*.csv)批量获取文件,不用手动逐个指定文件名 - 原来的
FlatFileItemReader配置(行映射、分隔策略等)完全可以复用,只需要移除单个资源的设置
方案二:动态传入文件列表(适合运行时指定文件)
如果你的文件路径需要在Job启动时动态指定(比如通过参数传递),可以用StepScope结合JobParameters实现:
@Bean @StepScope public MultiResourceItemReader<HotelCSVDto> dynamicMultiHotelReader( @Value("#{jobParameters['filePaths']}") String filePaths) { MultiResourceItemReader<HotelCSVDto> reader = new MultiResourceItemReader<>(); // 把传入的逗号分隔文件路径转成Resource数组 Resource[] resources = Arrays.stream(filePaths.split(",")) .map(path -> new ClassPathResource(path)) .toArray(Resource[]::new); reader.setResources(resources); reader.setDelegate(hotelCsvDelegateReader()); return reader; }
启动Job时通过参数传递多个文件路径:
JobParameters jobParameters = new JobParametersBuilder() .addString("filePaths", BASE_PATH + "Hotels-NY.csv," + BASE_PATH + "Hotels-LA.csv") .toJobParameters(); jobLauncher.run(hotelJob, jobParameters);
注意事项
- 确保所有CSV文件的结构完全一致(列数、列顺序、数据类型),否则
FieldSetMapper会抛出转换异常 - 如果处理大文件,建议开启Spring Batch的Chunk分片处理,避免内存溢出
- 若每个文件都有表头,可以在委托阅读器中用
setSkippedLinesCount(1)跳过第一行
内容的提问来源于stack exchange,提问作者JasminDan
相关产品推荐
相关产品推荐

