본문 바로가기

[업무 자동화] 자바로 엑셀 파일 읽어서 데이터 모으자

ironwhale 2024. 4. 10.

 매일 같이 우리는 회사에서 엑셀 파일을 이용해 자료를 작성하는데 엑셀파일에서 필요한 부분만 찾아서 모으고 싶을 때 일일이 파일을 열어서 복붙해야하는 노가다를 해야합니다. 
 
그럼에도 스프링이나 JPA를 이용해 엑셀 데이터를 데이터베이스에 저장하고자 했기때문에 자바로 엑셀 파일을 다루는 방법을 공부했습니다.   그래서 이번에 자바를 이용해 엑셀 파일을 읽어 데이터를 수집하는 방법에 대해 정리해보고자 합니다. 
 
그리고 다음과 같은 에러 발생 할때 해결 법도 알아보겠습니다.

ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...


순서

1. 라이브러리 설치

2. XSSWorkbook 인스턴스 생성 

3. XSSFSheet 인스턴스 생성

4. Row 접근

5. Cell   접근

 
값을 얻기 위해서는 cell에 접근해야되고 그러기 위해서는 2~4번까지의 과정이 필요합니다. 


1. 라이브러리 설치 

라이브러리는 poi라는 라이브러리를 사용합니다. 아래와 같이 poi-ooxml를 추가하고 새로고침을 하면 필요한 파일들을 자동으로 다운받습니다. 

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.5</version>
</dependency>

하지만 이것만 설치하면 ERROR StatusLogger Log4j2 could not find 이런 에러가 뜰 텐데 이건 아래의 라이브러리도 추가하면 사라집니다. 

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.23.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.23.1</version>
</dependency>

샘플 엑셀 파일

정말 간단한 예제 엑셀 파일을 이용해 루프를 돌려서 모든 데이터를 가져오는 법을 알아보겠습니다. 

 


2. XSSWorkbook 인스턴스 생성 

이제 가장 기초가 되는 엑셀파일 workbook를 생성합니다. XSSWorkbook 인스턴스를 생성하는 순서는 다음과 같습니다. 
 

  1. File인스턴스 만들기
    • path를 폴더의 경로로 넣고 file.listFiles() 메소드를 사용하면 폴더 내부의 모든 파일을 리스트 형태로도 받을 수 있습니다. 이번 시간에는 간단하게 엑셀파일 하나만 받아오는 예제이므로 직접 파일 경로를 입력하였습니다. 
  2. FileInputStream 인스턴스 만들기
    • 위에서 만든 File 인스턴스를 입력해 FileInputStream을 만듭니다. 
    • try~catch문을 안쓰면 아마도 경고창이 뜰것입니다.
  3. XSSFWorkbook 인스턴스 만들기 
    • FileInputStream을 입력해 workbook을 만듭니다. 
public class Main {
    public static void main(String[] args) {
        final String path = "./sample.xlsx";
        File file = new File(path);

        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
             } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. XSSFSheet 인스턴스 생성

엑셀파일을 열었으니 원하는 데이터가 있는 엑셀 시트로 들어가기 위해서 XSSFSheet 인스턴스를 만듭니다. 그리고 정말 간단하게 wb.getSheetAt(0) 메소드를 사용해서 만들 수 있습니다. 2번째 시트는 wb.getSheetAt(1)로 접근가능합니다.

public class Main {
    public static void main(String[] args) {

final String path = "./sample.xlsx";
        File file = new File(path);

        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
            XSSFSheet ws = workbook.getSheetAt(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

시트이름으로 접근하기

번외로 getSheet("시트이름")으로 시트에 접근도 가능합니다. 

workbook.getSheet("sheet1")

4. Row 접근

XSSFSheet로 만든 ws를  for 문으로 다음과 같이 Row row :ws 사용하면 각 행의 데이터에 접근할 수 있습니다. 

 
public class Main {
    public static void main(String[] args) {
        System.out.println("hello world");

        final String path = "./sample.xlsx";
        File file = new File(path);

        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
            XSSFSheet ws = workbook.getSheetAt(0);
            
            for (Row row : ws) {
               
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

특정 행 접근하기 

만약 특정 행에 접근하기를 원한다면 ws.getRow( 행의 인덱스) 를 사용하시면 됩니다. 

Row row1 = ws.getRow(1);

 


5. Cell   접근

자 이제 데이터를 불러오기 위한 마지막 단계 cell을 얻을 차례입니다. Row를 for문을 돌리면 Cell 인스턴스를 얻을 수 있습니다. 그리고 각 셀의 데이터의 형태에 따라 cell.getStringCellValue(), cell.getNumericCellValue를 사용해 우리가 원하는 엑셀 데이터를 가지고 올 수 있습니다. 

전체코드

public class Main {
    public static void main(String[] args) {
        System.out.println("hello world");

        final String path = "./sample.xlsx";
        File file = new File(path);

        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
            XSSFSheet ws = workbook.getSheetAt(0);
            
            for (Row row : ws) {
                for (Cell cell : row)
                    switch (cell.getCellType()) {
                        case STRING -> System.out.println("cell.getStringCellValue() = " + cell.getStringCellValue());
                        case NUMERIC ->
                                System.out.println("cell.getNumericCellValue() = " + cell.getNumericCellValue());
                    }
                System.out.println("===================================");
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

결괏값

cell.getStringCellValue() = name
cell.getStringCellValue() = age
cell.getStringCellValue() = hobby
===================================
cell.getStringCellValue() = LEE
cell.getNumericCellValue() = 20.0
cell.getStringCellValue() = computer
===================================
cell.getStringCellValue() = KIM
cell.getNumericCellValue() = 22.0
cell.getStringCellValue() = football
===================================
cell.getStringCellValue() = Park
cell.getNumericCellValue() = 25.0
cell.getStringCellValue() = fix car
===================================

번외 특정 셀의 값만 가지고 오기

위와 같이 잘 정리된 엑셀 데이터는  for문으로 손쉽게 데이터를 얻을 수 있습니다. 그냥 특정셀의 값을 바로 불러오기 위해 getRow와 getCell을 조합하여 바로 특정 셀의 값을 불러 올 수도 있습니다. 

 

ws.getRow(1).getCell(1).getNumericCellValue()

 


요약

  • 자바로 엑셀을 다루기 위해서는 poi라이브러리를 사용한다. 
  • 엑셀의 데이터를 접근하기 위해서는 Cell 인스턴스를 만들어야 된다. 
  • Cell 인스턴스는 Row 인스턴스로 부터 만든다.
  • Row인스턴스는 XSSFSheet 인스턴스로부터 만든다.
  • XSSFSheet 인스턴스는 XSSFWorkbook 인스턴스로 부터 만든다. 

자바를 꼭 써야되는 조건이 아니면 파이썬을 쓰는것이 더 간편한건 같습니다. 

댓글