乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 批处理概述与 Spring Batch 核心理念

    • Spring Batch 概述
    • Job-Instance-Execution 三层生命周期
    • 三层架构
    • Chunk 处理模型
    • Tasklet 处理模型
  • 第2章 Job与作业配置

    • Job 详解
    • Job 配置
    • JobLauncher 详解
    • JobParameters 详解
    • JobRepository 详解
  • 第3章 Step与执行模型

    • Step 详解
    • Step 配置
    • ExecutionContext 详解
    • ItemStream 与状态管理
    • StepScope 与 JobScope
  • 第4章 ItemReader数据读取

    • ItemReader 详解
    • FlatFileItemReader 详解
    • JdbcItemReader 详解
    • MultiResourceItemReader 详解
  • 第5章 ItemProcessor 数据处理

    • ItemProcessor 详解
  • 第6章 ItemWriter 数据写出

    • ItemWriter 详解
    • FlatFileItemWriter 详解
    • CompositeItemWriter 详解
    • JdbcBatchItemWriter 详解
  • 第7章 Chunk 处理与事务边界

    • Chunk 处理模型详解
    • 事务边界
  • 第8章 作业参数与启动

    • 命令行与 Web 启动
  • 第9章 监听器与拦截器

    • 监听器详解
  • 第10章 重启重试与跳过策略

    • 重启与重试
    • 跳过策略
  • 第11章 作业流与条件决策

    • 作业流与条件决策
  • 第12章 分区与并行处理

    • 分区详解
    • 并行 Step 与 Split
  • 第13章 与 Spring Boot 集成实践

    • Spring Boot 集成
  • 第15章 运维与监控

    • 大作业设计模式
    • 运维与监控

FlatFileItemReader 详解

本章定位:深入掌握 Spring Batch 最常用的文件读取器——FlatFileItemReader,覆盖 CSV、定长字段、自定义 LineTokenizer 和 FieldSetMapper 的完整用法。

定义与作用

FlatFileItemReader 是 Spring Batch 中用于读取平面文件(CSV、定长、TSV 等)的内置 Reader。它从 Resource 中逐行读取,通过 LineMapper 将每行文本转换为领域对象。

飞翔科技后端开发小崔在处理运营部高英的各种 CSV 文件时:

"FlatFileItemReader 就像一个智能流水线:LineTokenizer 把一行文本拆成字段,FieldSetMapper 把字段映射成对象。你只需要配置分隔符和字段名,剩下的解析、跳过空行、异常处理都交给框架。"

核心原理

核心组件职责

组件接口职责
Resourceorg.springframework.core.io.Resource定位文件(文件系统、classpath、URL)
LineMapperLineMapper<T>将一行文本映射为对象
LineTokenizerLineTokenizer将一行文本拆分为 FieldSet
FieldSetMapperFieldSetMapper<T>将 FieldSet 映射为领域对象

DefaultLineMapper 的处理流水线

完整示例

场景一:飞翔科技——CSV 格式学生成绩导入

背景:运营部高英提供了一个 5000 行的学生成绩 CSV。小崔用 FlatFileItemReader 读取。

grades.csv:

student_id,course_name,score
STU001,数据结构,85
STU002,操作系统,92
STU003,计算机网络,78
@Configuration
public class GradeReaderConfig {

    @Bean
    @StepScope
    public FlatFileItemReader<GradeDTO> gradeReader(
            @Value("#{jobParameters['input.file']}") String inputFile) {

        DefaultLineMapper<GradeDTO> lineMapper = new DefaultLineMapper<>();

        // Step 1: Tokenizer——按逗号拆分
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
        tokenizer.setDelimiter(",");
        tokenizer.setNames("studentId", "courseName", "score");
        tokenizer.setStrict(false);  // 字段数不匹配时不抛异常
        lineMapper.setLineTokenizer(tokenizer);

        // Step 2: FieldSetMapper——字段映射为对象
        BeanWrapperFieldSetMapper<GradeDTO> fieldSetMapper =
                new BeanWrapperFieldSetMapper<>();
        fieldSetMapper.setTargetType(GradeDTO.class);
        lineMapper.setFieldSetMapper(fieldSetMapper);

        return new FlatFileItemReaderBuilder<GradeDTO>()
                .name("gradeReader")
                .resource(new FileSystemResource(inputFile))
                .lineMapper(lineMapper)
                .linesToSkip(1)           // 跳过标题行
                .encoding("UTF-8")
                .strict(true)
                .build();
    }
}

场景二:定长文件读取——银行对账文件

金融行业的定长文件,每列固定宽度:

20260613STU001张三     数据结构  085
20260613STU002李四     操作系统  092
@Bean
public FlatFileItemReader<BankRecord> fixedLengthReader() {
    return new FlatFileItemReaderBuilder<BankRecord>()
            .name("fixedLengthReader")
            .resource(new FileSystemResource("bank_records.txt"))
            .fixedLength()
            .columns(new Range(1, 8),    // 日期
                     new Range(9, 14),   // 学号
                     new Range(15, 20),  // 姓名
                     new Range(21, 30),  // 课程
                     new Range(31, 33))  // 分数
            .names("date", "studentId", "name", "course", "score")
            .targetType(BankRecord.class)
            .strict(true)
            .build();
}

操作前后对比:

维度手动 BufferedReaderFlatFileItemReader
行解析line.split(",")DelimitedLineTokenizer
字段映射手动 new GradeDTO() + setXxx()BeanWrapperFieldSetMapper 自动映射
异常处理try-catch 包裹通过 strict 和容错策略声明式处理
续读手动记录行号框架自动通过 ExecutionContext 管理
编码手动指定encoding("UTF-8")
跳过空行手动判断框架自动跳过

易错场景与避坑

反例一:字段名和 DTO 属性名不匹配

// ❌ CSV 文件头: studentId,name,age
// ❌ DTO 属性: id,studentName,age
tokenizer.setNames("studentId", "name", "age");
fieldSetMapper.setTargetType(StudentDTO.class);
// BeanWrapperFieldSetMapper 按名称匹配 → name 字段无法映射!

正确做法:确保 setNames() 中的字段名和 DTO 的属性名完全一致(区分大小写)。

反例二:strict=true + 文件不存在

// ❌ strict=true 但文件路径拼写错误
return new FlatFileItemReaderBuilder<GradeDTO>()
        .name("reader")
        .resource(new FileSystemResource("wrong_path.csv"))
        .strict(true)  // 文件不存在 → IllegalStateException
        .build();

正确做法:生产环境使用 @StepScope + @Value 从 JobParameters 动态获取文件路径,确保参数校验在 Step 执行前完成。

面试高频考点

Q1:DefaultLineMapper 的工作流程?

mapLine(line, lineNumber) → LineTokenizer 将字符串拆分为 FieldSet → FieldSetMapper 将 FieldSet 映射为领域对象。两个步骤可独立替换(如改用 PatternMatchingCompositeLineMapper 根据行前缀选择不同的映射策略)。

Q2:如何处理 CSV 中包含分隔符的字段(如 "北京,朝阳区")?

使用 DelimitedLineTokenizer 时,框架默认不支持引号转义。如果 CSV 包含逗号的字段用双引号包裹,需要自定义 LineTokenizer,或使用 OpenCSV 等第三方库替代默认的 tokenizer。


上一章:ItemReader 详解下一章:JdbcItemReader 详解

上一页
ItemReader 详解
下一页
JdbcItemReader 详解