[파일처리] 2. FlatFileItemReader 다양한 파일 읽기 전략

y001·2026년 3월 8일

Spring Batch Guide

목록 보기
12/19
post-thumbnail

1. CSV 파일 처리

CSV 파일은 가장 일반적인 파일 형식이며, 구분자를 기준으로 데이터를 분리하는 구조를 가진다. Spring Batch에서는 DelimitedLineTokenizer를 사용하여 CSV 데이터를 처리한다.

예를 들어 다음과 같은 CSV 파일이 있다고 가정한다.

errorId,errorTime,severity,processId,message
ERR001,2024-01-19 10:15:23,CRITICAL,1234,SYSTEM_CRASH
ERR002,2024-01-19 10:15:25,FATAL,1235,MEMORY_OVERFLOW

Spring Batch에서는 다음과 같이 Reader를 구성할 수 있다.

@Bean
public FlatFileItemReader<SystemFailure> reader() {

    return new FlatFileItemReaderBuilder<SystemFailure>()
            .name("systemFailureReader")
            .resource(new ClassPathResource("system_failure.csv"))
            .linesToSkip(1)
            .delimited()
            .delimiter(",")
            .names(
                "errorId",
                "errorTime",
                "severity",
                "processId",
                "message"
            )
            .targetType(SystemFailure.class)
            .build();
}

delimited() 설정을 사용하면 내부적으로 DelimitedLineTokenizer가 적용된다. Tokenizer는 CSV 문자열을 필드 단위로 분리하고 FieldSet을 생성하며, 이후 FieldSetMapper를 통해 도메인 객체로 변환된다.

2. RegexLineTokenizer

로그 파일처럼 문자열 구조가 일정하지 않거나 복잡한 패턴을 가지는 경우에는 RegexLineTokenizer를 사용할 수 있다.

예를 들어 다음과 같은 로그 문자열을 처리한다고 가정한다.

[ERROR][Thread-157][CPU:92%] Thread deadlock detected

이 경우 정규식을 이용해 데이터를 분리할 수 있다.

@Bean
public LineTokenizer tokenizer() {

    RegexLineTokenizer tokenizer = new RegexLineTokenizer();

    tokenizer.setRegex("\\[(.*?)\\]\\[(.*?)\\]\\[(.*?)\\] (.*)");
    tokenizer.setNames(
        "level",
        "thread",
        "cpu",
        "message"
    );

    return tokenizer;
}

RegexLineTokenizer는 정규식의 캡처 그룹을 기준으로 문자열을 분리하여 FieldSet을 생성한다. 이를 통해 구조가 일정하지 않은 로그 데이터도 안정적으로 파싱할 수 있다.

3. PatternMatchingCompositeLineMapper

하나의 파일 안에 여러 형식의 데이터가 섞여 있는 경우에는 PatternMatchingCompositeLineMapper를 사용할 수 있다.

예를 들어 다음과 같은 로그 파일이 있다고 가정한다.

ERROR,ERR001,2024-01-19,SYSTEM_CRASH
INFO,Service started
WARN,Memory usage high

각 라인의 구조가 다르기 때문에 패턴에 따라 서로 다른 Tokenizer를 적용해야 한다.

PatternMatchingCompositeLineMapper<Object> lineMapper =
        new PatternMatchingCompositeLineMapper<>();

Map<String, LineTokenizer> tokenizers = new HashMap<>();

tokenizers.put("ERROR*", errorTokenizer());
tokenizers.put("INFO*", infoTokenizer());
tokenizers.put("WARN*", warnTokenizer());

lineMapper.setTokenizers(tokenizers);

PatternMatchingCompositeLineMapper는 라인의 패턴을 검사한 뒤 해당 패턴에 맞는 Tokenizer를 선택하여 데이터를 처리한다. 이를 통해 하나의 파일 안에서 여러 형식의 데이터를 처리할 수 있다.

4. MultiResourceItemReader

실제 배치 환경에서는 하나의 파일이 아니라 여러 개의 파일을 순차적으로 처리해야 하는 경우가 많다. 예를 들어 다음과 같은 파일이 있다고 가정한다.

log-20240101.csv
log-20240102.csv
log-20240103.csv

이 경우 MultiResourceItemReader를 사용하여 여러 파일을 하나의 Reader처럼 처리할 수 있다.

@Bean
public MultiResourceItemReader<SystemFailure> multiReader() {

    MultiResourceItemReader<SystemFailure> reader =
            new MultiResourceItemReader<>();

    reader.setResources(new Resource[] {
            new ClassPathResource("log-20240101.csv"),
            new ClassPathResource("log-20240102.csv"),
            new ClassPathResource("log-20240103.csv")
    });

    reader.setDelegate(reader());

    return reader;
}

MultiResourceItemReader는 여러 파일을 순차적으로 읽으며 내부적으로 지정된 Reader(FlatFileItemReader)를 사용하여 데이터를 처리한다.

0개의 댓글