[Java] FileStream 을 ByteArrayStream 으로 바꿔 불필요한 file 생성 피하기

jomminii·2022년 9월 22일
1

java

목록 보기
2/2

비즈니스 로직 중 가공한 데이터를 엑셀로 가공해서 S3로 올리는 로직이 있습니다. apache.poi 라이브러리 중 Workbook 을 활용하는건데요.

처음 로직을 작성할 때는 엑셀 저장을 위한 파일을 만들고, FileOutputStream을 통해 엑셀 내용을 담아 이 파일 자체를 S3에 업로드 하는 로직을 짰습니다.


private <T> String dealWithExcel(List<ExcelData> excelData, HttpServletResponse response) {
    Date currentDate = new Date();

    String fileName = "fileName";
    File newExcelFile = new File(fileName);

    ExcelCreator<T> excelCreator = makeDataForExcel(excelData, currentDate);

    try (ExcelWorkbook excelWorkbook = excelCreator.createExcel();
        FileOutputStream fileOutputStream = new FileOutputStream(newExcelFile);
    ) {
        excelS3Upload(newExcelFile, excelWorkbook, fileOutputStream);

        return fileName;
    } catch (Exception e) {
        log.warn("dealWithExcel error : ", e);
    } finally {
        File f = new File(fileName);
        if (f.exists()) {
            f.delete();
        }
    }
    ...
}

private void excelS3Upload(File resultExcelFile, ExcelWorkbook excelWorkbook, FileOutputStream fileOutputStream)
    throws IOException {
    excelWorkbook.write(fileOutputStream);
    ObjectMetadata objectMetadata = getObjectMetadata();

    s3Adapter.putObject(filePath, resultExcelFile, objectMetadata);
}

처음 짰을 때는 처음OutputStream 개념을 사용한거라 뿌듯하기도 했는데, 이상하게 테스트나 api 를 호출해보면 디스크에 엑셀 파일이 생성되더라고요.

그래서 찾아보니 파일은 new File 로 파일을 만들었으니 파일은 무조건 생기는 것 같고 이걸 지워야겠다 생각해서 파일을 삭제하는 로직을 finally 에 추가했습니다.


        File f = new File(fileName);
        if (f.exists()) {
            f.delete();
        }

그럼에도 뭔가 찝찝하긴 했는데 코드리뷰를 받고 나니 파일을 아예 생성하지 않고 엑셀을 업로드 할 수 있는 방법이 있는걸 알게 됐습니다.

S3에서 파일이 아닌 InputStream으로 변환해서 올려도 put이 가능하도록 관련 메소드를 제공하고 있었고, 최초에 OutputStream에 엑셀 내용을 받을 때도 파일이 아닌 ByteArray 를 통해 출력 내용을 담을 수 있었습니다.

그래서 파일을 생성하는 로직을 제거하고, ByteArrayOutputStream에 엑셀 데이터를 출력하도록 담고, 이 데이터를 ByteArray에 담은 다음, 이걸 읽는 ByteArrayInputStream을 생성했습니다.

마지막으로 이 InputStream을 s3 put object 메소드를 이용해 업로드해주었습니다.


private <T> String dealWithExcel(List<ExcelData> excelData, HttpServletResponse response) {
    Date currentDate = new Date();
    String fileName = "fileName";

    ExcelCreator<T> excelCreator = makeDataForExcel(excelData, currentDate);

    try (ExcelWorkbook excelWorkbook = excelCreator.createExcel()
    ) {
        excelS3Upload(excelWorkbook);

        return fileName;
    } catch (Exception e) {
        log.warn("dealWithExcel error : ", e);
    }
    ...
}

private void excelS3Upload(ExcelWorkbook excelWorkbook)
    throws IOException {
        ByteArrayInputStream bis = null;
        try (
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ) {
            excelWorkbook.write(bos);
            byte[] excelBytes = bos.toByteArray();
            bis = new ByteArrayInputStream(excelBytes);

            ObjectMetadata objectMetadata = getObjectMetadata();
            s3Adapter.putObject(filePath, bis, objectMetadata);
        } finally {
            if (bis != null) {
                bis.close();
            }
        }
}

이렇게 로직을 바꾸니 파일을 굳이 생성하지 않아도 되서 불필요한 IO 가 생기지 않게 되었고, 파일 삭제 로직 또한 빼도 되었습니다.

excelS3Upload에 필요한 파라미터도 많이 줄어들어서 보기 더 깔끔해졌습니다.

이번 경험을 통해서 Stream을 활용하는 방법을 하나 더 알아가네요!

profile
고민은 격렬하게, 행동은 단순하게

0개의 댓글