[ 스프링 배치 입문 #5 ] - 파일 읽고 쓰기

정동욱·2023년 7월 5일
0
post-thumbnail

이번 글에서는 csv 파일을 읽어 다른 형태로 작업 후 txt 파일로 쓰는 방법에 대해 알아보겠습니다.

먼저 FileReadWriteConfig 클래스를 만들고 의존관계를 주입합니다.

@Configuration
@RequiredArgsConstructor
public class FileReadWriteConfig {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

}

그리고 이번에 읽어들일 csv 파일을 보면 가장 첫줄이 컬럼명이고 그 아래부터는 컬럼의 데이터입니다.

ID,lastName,firstName,position,birthYear,debutYear
AbduKa00,Abdul-Jabbar,Karim,rb,1974,1996
AbduRa00,Abdullah,Rabih,rb,1975,1999
AberWa00,Abercrombie,Walter,rb,1959,1982
AbraDa00,Abramowicz,Danny,wr,1945,1967
AdamBo00,Adams,Bob,te,1946,1969
AdamCh00,Adams,Charlie,wr,1979,2003

그런 다음 FlatFileItemReader와 ItemProcessor 그리고 FlatFileItemWriter 세 객체를 매서드를 통해 만들어보겠습니다. 먼저 이번의 경우 읽어야 할 대상이 파일이기 때문에 ItemReader의 자손인 FlatFileItemReader를 이용합니다.

    // 리더
    @Bean
    @StepScope
    public FlatFileItemReader<Player> playerFlatFileItemReader() {
        return new FlatFileItemReaderBuilder<>()
                .name("playerFlatFileItemReader")
                .resource(new FileSystemResource("players.csv"))
                .lineTokenizer(new DelimitedLineTokenizer())
                .fieldSetMapper(new PlayerFieldSetMapper())
                .linesToSkip(1)
                .build();
    }

중간에 보이는 이 코드는 별도로 csv 파일에서 읽은 데이터를 전달하지 않아도 csv에서 읽은 한 줄의 데이터를 하나의 객체로 만드는 기능을 합니다.

.fieldSetMapper((FieldSetMapper)new PlayerFieldSetMapper())

PlayerFieldSetMapper 클래스는 아래와 같습니다.

public class PlayerFieldSetMapper implements FieldSetMapper<Player> {

    public Player mapFieldSet(FieldSet fieldSet) {
        Player player = new Player();

        player.setID(fieldSet.readString(0));
        player.setLastName(fieldSet.readString(1));
        player.setFirstName(fieldSet.readString(2));
        player.setPosition(fieldSet.readString(3));
        player.setBirthYear(fieldSet.readInt(4));
        player.setDebutYear(fieldSet.readInt(5));

        return player;
    }
}

그리고 ItemProcessor에서는 ItemReader를 통해 받은 Player 객체를 PlayerYears 객체로 변환합니다.

    // 프로세서
    @Bean
    @StepScope
    public ItemProcessor<Player, PlayerYears> playerPlayerYearsItemProcessor() {
        return new ItemProcessor<Player, PlayerYears>() {
            @Override
            public PlayerYears process(Player item) throws Exception {
                return new PlayerYears(item);
            }
        };
    }

마지막으로 파일을 쓰는 FlatFileItemWriter에서는 처리한 데이터로 txt 파일을 만듭니다.

    // 라이터
    @Bean
    @StepScope
    public FlatFileItemWriter<PlayerYears> playerYearsItemWriter() {
        BeanWrapperFieldExtractor<PlayerYears> fieldExtractor = new BeanWrapperFieldExtractor<>();
        fieldExtractor.setNames(new String[]{"ID", "lastName", "position", "yearsExperience"});
        fieldExtractor.afterPropertiesSet();

        DelimitedLineAggregator<PlayerYears> lineAggregator = new DelimitedLineAggregator<>();
        lineAggregator.setDelimiter(",");
        lineAggregator.setFieldExtractor(fieldExtractor);

        FileSystemResource outputResource = new FileSystemResource("player_output.txt");

        return new FlatFileItemWriterBuilder<PlayerYears>()
                .name("playerYearsItemWriter")
                .resource(outputResource)
                .lineAggregator(lineAggregator)
                .build();
    }

결과물은 이렇습니다.

AbduKa00,Abdul-Jabbar,rb,27
AbduRa00,Abdullah,rb,24
AberWa00,Abercrombie,rb,41
AbraDa00,Abramowicz,wr,56
AdamBo00,Adams,te,54
AdamCh00,Adams,wr,20

다음 글에서는 2개 이상의 Step을 등록하는 방법과 스텝 간의 분기처리하는 방법에 대해 알아보겠습니다.

profile
거인의 어깨 위에서 탭댄스를

0개의 댓글