Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ihoneymon/a1c1061f81528f153b7555f25323b1fb to your computer and use it in GitHub Desktop.
Save ihoneymon/a1c1061f81528f153b7555f25323b1fb to your computer and use it in GitHub Desktop.
별다른 라이브러리를 사용하지 않고 JDK 만 이용해서 파일읽고쓰기 기능 구현

JAVA - 간단한 CSV 쓰고 읽기

별다른 라이브러리를 사용하지 않고 JDK 만 이용해서 파일읽고쓰기 기능 구현

CsvSheet.java

import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Getter
@NoArgsConstructor
public class CsvSheet {
    public static final String DELIMITER = ",";
    public static final String SUFFIX_LINE_OF_END = "\n";

    private Row header;
    private List<Row> rows = new ArrayList<>();


    public CsvSheet registerHeader(Row header) {
        this.header = header;
        return this;
    }

    public boolean hasHeader() {
        return Objects.nonNull(this.header);
    }

    public CsvSheet addRow(Row row) {
        this.rows.add(row);
        return this;
    }

    public List<String> getHeadlessRows() {
        return rows.stream().map(Row::getStringRow).collect(Collectors.toList());
    }

    public List<String> getTotalRows() {
        if (hasHeader()) {
            List<String> list = new ArrayList<>();
            list.add(header.getStringRow());
            list.addAll(getHeadlessRows());
            return list;
        }

        return getHeadlessRows();
    }

    public CsvSheet addRows(List<Row> rows) {
        this.rows.addAll(rows);
        return this;
    }

    @NoArgsConstructor
    public static class Row<T> {
        private List<Cell<T>> cells = new ArrayList<>();

        public Row(T... objs) {
            this.cells = Stream.of(objs)
                .map(Cell::new)
                .collect(Collectors.toList());
        }

        public Row addCell(Object value) {
            this.cells.add(new Cell(value));
            return this;
        }

        public String getStringRow() {
            return cells.stream().map(Cell::getStringValue)
                .collect(Collectors.joining(DELIMITER, "", SUFFIX_LINE_OF_END));
        }
    }

    @Getter
    public static class Cell<T> {
        private T value;

        public Cell(T value) {
            this.value = value;
        }

        public String getStringValue() {
            return getValue().toString();
        }
    }
}

CsvFileWriter.java

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

@Slf4j
public class CsvFileWriter {
    public static final String FILE_EXTENSION = "csv";

    public void write(String fileName, CsvSheet csvSheet) {
        String csvFileName = getSourceFile(fileName);
        log.info("Generate csv file: {}", csvFileName);

        File file = new File(csvFileName);
        if (!file.exists()) {
            create(file, csvSheet);
        }

        append(csvFileName, csvSheet);
    }

    private void append(String csvFileName, CsvSheet csvSheet) {
        try (FileWriter fw = new FileWriter(csvFileName, true)) {
            StringBuilder stringBuilder = new StringBuilder();

            for (String strRow : csvSheet.getHeadlessRows()) {
                stringBuilder.append(strRow);
            }

            fw.write(stringBuilder.toString());
            fw.flush();
        } catch (IOException e) {
            log.error("CSV file append exception", e);
            throw new IllegalStateException("CSV file append exception", e);
        }
    }

    private void create(File file, CsvSheet csvSheet) {
        try (FileWriter fw = new FileWriter(file)) {
            if (csvSheet.hasHeader()) {
                fw.write(csvSheet.getHeader().getStringRow());
            } else {
                fw.write("\n");
            }
        } catch (IOException e) {
            log.error("CSV File Create Exception", e);
            throw new IllegalStateException("CSV File Create Exception", e);
        }
    }

    public void delete(String fileName) throws IOException {
        String csvFileName = getSourceFile(fileName);
        log.info("Generate csv file: {}", csvFileName);
        Files.delete(Paths.get(fileName));
    }

    private String getSourceFile(String fileName) {
        return String.format("%s.%s", fileName, FILE_EXTENSION);
    }
}

CsvFileReader.java

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

@Slf4j
public class CsvFileReader {
    public CsvSheet read(String fileName) {
        File file = new File(fileName);
        if (!file.exists()) {
            throw new IllegalArgumentException(String.format("요청하신 CSV 파일(이름: %s)이 존재하지 않습니다.", fileName));
        }

        CsvSheet csvSheet = new CsvSheet();
        try (FileReader filereader = new FileReader(file);
             BufferedReader bufReader = new BufferedReader(filereader)) {

            int rowCount = 0;
            String line;
            while ((line = bufReader.readLine()) != null) {
                if (rowCount == 0) {
                    CsvSheet.Row header = new CsvSheet.Row(line.split(CsvSheet.DELIMITER));
                    csvSheet.registerHeader(header);
                } else {
                    csvSheet.addRow(new CsvSheet.Row(line.split(CsvSheet.DELIMITER)));
                }
                rowCount++;
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("CSV 파일을 읽던 중 오류가 발생했습니다.", e);
        }

        return csvSheet;
    }
}

테스트 코드

CsvSheetTest.java

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class CsvSheetTest {

    @Test
    @DisplayName("CsvSheet - 헤더없음")
    void test01() {
        //expect
        CsvSheet csvSheet = new CsvSheet();

        //then
        assertThat(csvSheet.hasHeader()).isFalse();
        assertThat(csvSheet.getRows()).isEmpty();
        assertThat(csvSheet.getTotalRows()).isEmpty();
    }

    @Test
    @DisplayName("CsvSheet - 헤더확인")
    void test02() {
        //given
        CsvSheet csvSheet = new CsvSheet();

        //when
        CsvSheet.Row header = new CsvSheet.Row("header1", "header2", "header3");
        csvSheet.registerHeader(header);

        //when
        assertThat(csvSheet.hasHeader()).isTrue();
        assertThat(csvSheet.getTotalRows()).hasSize(1);
        assertThat(csvSheet.getTotalRows().get(0)).isEqualTo("header1,header2,header3\n");
    }

    @Test
    @DisplayName("CsvSheet - 본문추가")
    void test03() {
        //given
        CsvSheet csvSheet = new CsvSheet();

        //when
        CsvSheet.Row row1 = new CsvSheet.Row("row1-1", "row1-2", "row1-3");
        CsvSheet.Row row2 = new CsvSheet.Row("row2-1", "row2-2", "row2-3");
        CsvSheet.Row row3 = new CsvSheet.Row("row3-1", "row3-2", "row3-3");
        List<CsvSheet.Row> rows = Arrays.asList(row1, row2, row3);
        csvSheet.addRows(rows);

        assertThat(csvSheet.hasHeader()).isFalse();
        assertThat(csvSheet.getTotalRows()).hasSize(3);
        assertThat(csvSheet.getTotalRows().get(0)).isEqualTo("row1-1,row1-2,row1-3\n");
        assertThat(csvSheet.getTotalRows().get(1)).isEqualTo("row2-1,row2-2,row2-3\n");
        assertThat(csvSheet.getTotalRows().get(2)).isEqualTo("row3-1,row3-2,row3-3\n");
    }
}

CsvFileWriterTest.java

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class CsvFileWriterTest {
    CsvFileWriter csvFileWriter;
    private String fileName;

    @BeforeEach
    void setUp() {
        fileName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        csvFileWriter = new CsvFileWriter();
    }

    @AfterEach
    void tearDown() {
        File csvFile = new File(String.format("%s.%s", fileName, "csv"));
        csvFile.delete();
    }

    @Test
    @DisplayName("CsvFileWriter - 파일생성")
    void test01() {
        //given
        CsvSheet csvSheet = new CsvSheet();

        //when
        csvFileWriter.write(fileName, csvSheet);

        //then
        File csvFile = new File(String.format("%s.%s", fileName, "csv"));
        assertThat(csvFile.exists()).isTrue();
    }

    @Test
    @DisplayName("CsvFileWriter - 본문작성")
    void test02() throws IOException {
        //given
        CsvSheet csvSheet = new CsvSheet();
        CsvSheet.Row header = new CsvSheet.Row("header1", "header2", "header3");
        csvSheet.registerHeader(header);

        CsvSheet.Row row1 = new CsvSheet.Row("row1-1", "row1-2", "row1-3");
        CsvSheet.Row row2 = new CsvSheet.Row("row2-1", "row2-2", "row2-3");
        CsvSheet.Row row3 = new CsvSheet.Row("row3-1", "row3-2", "row3-3");
        List<CsvSheet.Row> rows = Arrays.asList(row1, row2, row3);
        csvSheet.addRows(rows);

        //when
        csvFileWriter.write(fileName, csvSheet);

        File csvFile = new File(String.format("%s.%s", fileName, "csv"));
        assertThat(csvFile.exists()).isTrue();

        List<String> strRows = readFile(csvFile);

        assertThat(strRows).hasSize(4);
        assertThat(strRows.get(0)).isEqualTo("header1,header2,header3");
        assertThat(strRows.get(1)).isEqualTo("row1-1,row1-2,row1-3");
        assertThat(strRows.get(2)).isEqualTo("row2-1,row2-2,row2-3");
        assertThat(strRows.get(3)).isEqualTo("row3-1,row3-2,row3-3");
    }

    private List<String> readFile(File csvFile) throws IOException {
        List<String> strRows = new ArrayList<>();
        try (FileReader filereader = new FileReader(csvFile);
             BufferedReader bufReader = new BufferedReader(filereader)) {

            String line;
            while ((line = bufReader.readLine()) != null) {
                strRows.add(line);
            }
        } catch (Exception e) {
            throw e;
        }
        return strRows;
    }

    @Test
    @DisplayName("CsvFileWriter - 붙여쓰기 확인")
    void test03() throws IOException {
        //given
        CsvSheet csvSheet = new CsvSheet();
        CsvSheet.Row header = new CsvSheet.Row("header1", "header2", "header3");
        csvSheet.registerHeader(header);

        CsvSheet.Row row1 = new CsvSheet.Row("row1-1", "row1-2", "row1-3");
        CsvSheet.Row row2 = new CsvSheet.Row("row2-1", "row2-2", "row2-3");
        CsvSheet.Row row3 = new CsvSheet.Row("row3-1", "row3-2", "row3-3");
        List<CsvSheet.Row> rows = Arrays.asList(row1, row2, row3);
        csvSheet.addRows(rows);

        csvFileWriter.write(fileName, csvSheet);

        CsvSheet otherCsvSheet = new CsvSheet();
        CsvSheet.Row row4 = new CsvSheet.Row("row4-1", "row4-2", "row4-3");
        CsvSheet.Row row5 = new CsvSheet.Row("row5-1", "row5-2", "row5-3");
        CsvSheet.Row row6 = new CsvSheet.Row("row6-1", "row6-2", "row6-3");
        List<CsvSheet.Row> otherRows = Arrays.asList(row4, row5, row6);
        otherCsvSheet.addRows(otherRows);

        csvFileWriter.write(fileName, otherCsvSheet);

        File csvFile = new File(String.format("%s.%s", fileName, "csv"));
        assertThat(csvFile.exists()).isTrue();


        List<String> strRows = readFile(csvFile);

        assertThat(strRows).hasSize(7);
        assertThat(strRows.get(0)).isEqualTo("header1,header2,header3");
        assertThat(strRows.get(1)).isEqualTo("row1-1,row1-2,row1-3");
        assertThat(strRows.get(2)).isEqualTo("row2-1,row2-2,row2-3");
        assertThat(strRows.get(3)).isEqualTo("row3-1,row3-2,row3-3");
        assertThat(strRows.get(4)).isEqualTo("row4-1,row4-2,row4-3");
        assertThat(strRows.get(5)).isEqualTo("row5-1,row5-2,row5-3");
        assertThat(strRows.get(6)).isEqualTo("row6-1,row6-2,row6-3");
    }
}

CsvFileReaderTest.java

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class CsvFileReaderTest {
    CsvFileWriter csvFileWriter;
    CsvFileReader csvFileReader;
    private String fileName;

    @BeforeEach
    void setUp() {
        fileName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        csvFileWriter = new CsvFileWriter();
        csvFileReader = new CsvFileReader();

        writeDummyData();
    }

    private void writeDummyData() {
        CsvSheet csvSheet = new CsvSheet();
        CsvSheet.Row header = new CsvSheet.Row("header1", "header2", "header3");
        csvSheet.registerHeader(header);

        CsvSheet.Row row1 = new CsvSheet.Row("row1-1", "row1-2", "row1-3");
        CsvSheet.Row row2 = new CsvSheet.Row("row2-1", "row2-2", "row2-3");
        CsvSheet.Row row3 = new CsvSheet.Row("row3-1", "row3-2", "row3-3");
        List<CsvSheet.Row> rows = Arrays.asList(row1, row2, row3);
        csvSheet.addRows(rows);

        csvFileWriter.write(fileName, csvSheet);
    }

    @AfterEach
    void tearDown() {
        File csvFile = new File(String.format("%s.%s", fileName, "csv"));
        csvFile.delete();
    }

    @Test
    @DisplayName("CsvFileReader - 존재하지 않는 파일 읽기 오류 발생")
    void test01() {
        assertThatThrownBy(() -> csvFileReader.read("NONE-EXIST-FILE"))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessage("요청하신 CSV 파일(이름: NONE-EXIST-FILE)이 존재하지 않습니다.");
    }

    @Test
    @DisplayName("CsvFileReader - 정상 파일읽기")
    void test02() {
        //expect
        CsvSheet csvSheet = csvFileReader.read(String.format("%s.%s", fileName, "csv"));

        //then
        assertThat(csvSheet.hasHeader()).isTrue();
        assertThat(csvSheet.getHeader().getStringRow()).isEqualTo("header1,header2,header3\n");
        assertThat(csvSheet.getHeadlessRows()).hasSize(3);
        assertThat(csvSheet.getHeadlessRows().get(0)).isEqualTo("row1-1,row1-2,row1-3\n");
        assertThat(csvSheet.getHeadlessRows().get(1)).isEqualTo("row2-1,row2-2,row2-3\n");
        assertThat(csvSheet.getHeadlessRows().get(2)).isEqualTo("row3-1,row3-2,row3-3\n");
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment