Spring Batch 如何读取文件特定区块的字段定义与实际数据?
Spring Batch 分区块文件读取实现方案
核心思路是通过自定义带状态控制的FlatFileItemReader,分两个阶段完成文件读取,全程不需要拆分多Step,逻辑更简洁。
具体实现步骤
- 第一步:给Reader增加状态标识,控制读取区间
定义三个读取状态:读取字段区、读取数据区、读取结束,初始状态为读取字段区:- 逐行读取文件,读到
START_OF_FIELDS标记后开始收集后续行内容作为目标字段,直到读到END_OF_FIELDS停止,把收集到的字段列表缓存在Reader内部,状态切换为读取数据区 - 继续逐行读取,读到
START_OF_DATA标记后,先解析第一行表头,拿到你缓存的目标字段对应的列下标,后续行按分隔符切分后只提取对应下标的值组装成数据对象,直到读到END_OF_DATA,状态切换为读取结束,返回null终止读取
- 逐行读取文件,读到
- 第二步:核心代码示例
// 自定义分段Reader public class SectionedFileReader extends FlatFileItemReader<Object> { // 读取状态枚举 private enum ReadState { READ_FIELD_SECTION, READ_DATA_SECTION, COMPLETE } private ReadState currentState = ReadState.READ_FIELD_SECTION; // 缓存的目标字段列表 private List<String> targetFields = new ArrayList<>(); // 表头与下标的映射关系 private Map<String, Integer> fieldIndexMap = new HashMap<>(); private final DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer("|"); @Override protected Object doRead() throws Exception { while (currentState != ReadState.COMPLETE) { String line = readLine(); if (line == null) break; // 处理字段配置区 if (currentState == ReadState.READ_FIELD_SECTION) { if (line.equals("START_OF_FIELDS")) continue; if (line.equals("END_OF_FIELDS")) { currentState = ReadState.READ_DATA_SECTION; continue; } targetFields.add(line.trim()); continue; } // 处理数据区 if (currentState == ReadState.READ_DATA_SECTION) { if (line.equals("START_OF_DATA")) continue; if (line.equals("END_OF_DATA")) { currentState = ReadState.COMPLETE; continue; } // 首次进入数据区先处理表头,建立映射关系 if (fieldIndexMap.isEmpty()) { String[] headers = tokenizer.tokenize(line).getValues(); for (int i = 0; i < headers.length; i++) { fieldIndexMap.put(headers[i], i); } continue; } // 只提取目标字段对应的值 FieldSet lineContent = tokenizer.tokenize(line); Map<String, String> data = new HashMap<>(); for (String field : targetFields) { data.put(field, lineContent.readString(fieldIndexMap.get(field))); } // 此处可替换为你自定义的业务实体类返回 return data; } } return null; } }
- 第三步:装配到Step即可使用
直接把自定义Reader注入到普通的Step配置中,后续的Processor和Writer正常处理Reader返回的数据即可,不需要额外做跨Step上下文传递。
注意:你给出的示例文件中
START_OF_FIELDS标记拼写错误为STARRT_OF_FIELDS,实际使用时请先确认文件标记的正确性,避免匹配失败。
内容的提问来源于stack exchange,提问作者TechieGirl
相关产品推荐
相关产品推荐

