[백업][가리사니] 자바 엑셀 데이터 읽기 : 입력한 형식대로만 읽어오기
java

이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.

서론

엑셀 리더를 작성할 일이 있어 올려봅니다.

테스트 데이터

C:/abc.xlsx C:/abc.xls 각각 저장

아파치 poi-ooxml 를 디팬던시에 등록합니다.

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

일반적인 사용

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;

/**
 * 엑셀 jexcelapi test
 */
public class ExcelReadTest {
	@Test
	public void excelRead() throws FileNotFoundException, IOException {
		List<String> paths = Arrays.asList("C:/abc.xlsx", "C:/abc.xls");

		for (String path : paths)  {
			Workbook tempWorkbook;

			if (path.endsWith(".xls")) {
				tempWorkbook = new HSSFWorkbook(new FileInputStream(path));
			}
			else if (path.endsWith(".xlsx")) {
				tempWorkbook = new XSSFWorkbook(new FileInputStream(path));
			}
			else {
				throw new IllegalAccessError("xls / xlsx 확장자만 읽을 수 있습니다.");
			}

			try (Workbook workbook = tempWorkbook) {
				System.out.println("경로 : " + path);
				Sheet sheet = workbook.getSheetAt(0);
				System.out.println("첫번째 sheet 읽음");

				// 행을 가져옵니다.
				for (Row row : sheet) {
					// cell (행의 각 열) 을 가져옵니다.
					row.forEach(cell -> {
						System.out.print(cell.toString());
						System.out.print(" || ");
					});
					System.out.println();
				}
			}
		}
	}
}

결과 : 경로 : C:/abc.xlsx 첫번째 sheet 읽음 그냥숫자 || 그냥문자 || 아무거나 || 날짜 || 332492.0 || 안녕하세요 || 3234.23 || 30-10월-2011 || 23422.0 || 가리사니 || 3234.23 || 31-10월-2011 || 234234.0 || 개발자 || 3234.23 || 01-11월-2011 || 234234.0 || 공간 || 3234.23 || 02-11월-2011 || 234234.0 || 입니다. || 3234.23 || 03-11월-2011 || 234111.0 || 테스트 || 3234.23 || 04-11월-2011 || 3679.0 || 문서 || 3234.23 || 05-11월-2011 || 2134234.0 || 입니다. || 3234.23 || 06-11월-2011 || 경로 : C:/abc.xls 첫번째 sheet 읽음 그냥숫자 || 그냥문자 || 아무거나 || 날짜 || 332492.0 || 안녕하세요 || 3234.23 || 30-10월-2011 || 23422.0 || 가리사니 || 3234.23 || 31-10월-2011 || 234234.0 || 개발자 || 3234.23 || 01-11월-2011 || 234234.0 || 공간 || 3234.23 || 02-11월-2011 || 234234.0 || 입니다. || 3234.23 || 03-11월-2011 || 234111.0 || 테스트 || 3234.23 || 04-11월-2011 || 3679.0 || 문서 || 3234.23 || 05-11월-2011 || 2134234.0 || 입니다. || 3234.23 || 06-11월-2011 || 숫자와 날짜가.. 심각합니다….

일반적인 사용

  • 위 방법은 포멧을 마음대로 바꿔버리는 단점때문에 DataFormatter 를 써보도록 하겠습니다. ``` java import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Arrays; import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.Test;

/**

  • 엑셀 jexcelapi test */ public class ExcelReadTest { @Test public void excelRead() throws FileNotFoundException, IOException { List paths = Arrays.asList("C:/abc.xlsx", "C:/abc.xls"); // 데이터 포멧터 DataFormatter formatter = new DataFormatter();

     for (String path : paths) {
         Workbook tempWorkbook;
    
         if (path.endsWith(".xls")) {
             tempWorkbook = new HSSFWorkbook(new FileInputStream(path));
         }
         else if (path.endsWith(".xlsx")) {
             tempWorkbook = new XSSFWorkbook(new FileInputStream(path));
         }
         else {
             throw new IllegalAccessError("xls / xlsx 확장자만 읽을 수 있습니다.");
         }
    
         try (Workbook workbook = tempWorkbook) {
             System.out.println("경로 : " + path);
             Sheet sheet = workbook.getSheetAt(0);
             System.out.println("첫번째 sheet 읽음");
    
             // 행을 가져옵니다.
             for (Row row : sheet) {
                 // cell (행의 각 열) 을 가져옵니다.
                 row.forEach(cell -> {
                     // 데이터 포멧터 사용.
                     System.out.print(formatter.formatCellValue(cell));
                     System.out.print(" || ");
                 });
                 System.out.println();
             }
         }
     }  } } ``` 결과 : 경로 : C:/abc.xlsx 첫번째 sheet 읽음 그냥숫자 || 그냥문자 || 아무거나 || 날짜 || 332492 || 안녕하세요 || 3234.23 || 10/30/11 || 23422 || 가리사니 || 3234.23 || 10/31/11 || 234234 || 개발자 || 3234.23 || 11/1/11 || 234234 || 공간 || 3234.23 || 11/2/11 || 234234 || 입니다. || 3234.23 || 11/3/11 || 234111 || 테스트 || 3234.23 || 11/4/11 || 3679 || 문서 || 3234.23 || 11/5/11 || 2134234 || 입니다. || 3234.23 || 11/6/11 || 경로 : C:/abc.xls 첫번째 sheet 읽음 그냥숫자 || 그냥문자 || 아무거나 || 날짜 || 332492 || 안녕하세요 || 3234.23 || 10/30/11 || 23422 || 가리사니 || 3234.23 || 10/31/11 || 234234 || 개발자 || 3234.23 || 11/1/11 || 234234 || 공간 || 3234.23 || 11/2/11 || 234234 || 입니다. || 3234.23 || 11/3/11 || 234111 || 테스트 || 3234.23 || 11/4/11 || 3679 || 문서 || 3234.23 || 11/5/11 || 2134234 || 입니다. || 3234.23 || 11/6/11 || 숫자는 제대로 나오지만 불행이도 날짜가... 아주 불행하게도 예외 처리 없이 처리할 방법이 없는 것 같습니다. xsl 지원을 포기하고 XSSFCell 로 가더라도 getRawValue 가 날짜형에선 입력한 대로 나오지 않습니다. 그럼 어떤 포멧을 예외처리해줘야할까 아래 사이트에 들어가봤습니다. 참고 : http://stackoverflow.com/questions/34918775/xlsx-issue-cell-getcellstyle-getdataformat-changing-value-after-adding-or-r ``` java int dataFormat = cell.getCellStyle().getDataFormat(); if (dataFormat  == 14) {  dateFmt = "dd/mm/yyyy"; } else if(dataFormat  == 165) {  dateFmt = "m/d/yy"; } else if(dataFormat  == 166) {  dateFmt = "d-mmm-yy"; } else if(dataFormat  == 167) {  dateFmt = "mmmm d yyyy "; } else if(dataFormat  == 168) {  dateFmt = "m/d/yyyy"; } else if(dataFormat  == 169) {  dateFmt = "d-mmm-yyyy"; } ``` 매우 다행이도 위처럼 처리할 필요없이 poi 의 HSSFDateUtil 에 아래와 같이 작성된 부분이 있습니다. ``` java  /**
    
  • Given a format ID this will check whether the format represents
  • an internal excel date format or not.
  • @see #isADateFormat(int, java.lang.String) */ public static boolean isInternalDateFormat(int format) { switch(format) { // Internal Date Formats as described on page 427 in // Microsoft Excel Dev’s Kit… case 0x0e: case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x2d: case 0x2e: case 0x2f: return true; } return false; } ``` 그럼 코드를 고쳐보겠습니다.

날짜 예외 처리

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;

/**
 * 엑셀 jexcelapi test
 */
public class ExcelReadTest {
	@Test
	public void excelRead() throws FileNotFoundException, IOException {
		List<String> paths = Arrays.asList("C:/abc.xlsx", "C:/abc.xls");
		// 데이터 포멧터
		DataFormatter formatter = new DataFormatter();
		// 데이트 포맷
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

		for (String path : paths) {
			Workbook tempWorkbook;

			if (path.endsWith(".xls")) {
				tempWorkbook = new HSSFWorkbook(new FileInputStream(path));
			}
			else if (path.endsWith(".xlsx")) {
				tempWorkbook = new XSSFWorkbook(new FileInputStream(path));
			}
			else {
				throw new IllegalAccessError("xls / xlsx 확장자만 읽을 수 있습니다.");
			}

			try (Workbook workbook = tempWorkbook) {
				System.out.println("경로 : " + path);
				Sheet sheet = workbook.getSheetAt(0);
				System.out.println("첫번째 sheet 읽음");

				// 행을 가져옵니다.
				for (Row row : sheet) {
					// cell (행의 각 열) 을 가져옵니다.
					row.forEach(cell -> {
						String value;
						// 날짜형 예외
						if (HSSFDateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat())) {
							value = sdf.format(cell.getDateCellValue());
						}
						// 기타
						else {
							value = formatter.formatCellValue(cell);
						}
						System.out.print(value);
						System.out.print(" || ");
					});
					System.out.println();
				}
			}
		}
	}
}

출력 : 경로 : C:/abc.xlsx 첫번째 sheet 읽음 그냥숫자 || 그냥문자 || 아무거나 || 날짜 || 332492 || 안녕하세요 || 3234.23 || 2011-10-30 || 23422 || 가리사니 || 3234.23 || 2011-10-31 || 234234 || 개발자 || 3234.23 || 2011-11-01 || 234234 || 공간 || 3234.23 || 2011-11-02 || 234234 || 입니다. || 3234.23 || 2011-11-03 || 234111 || 테스트 || 3234.23 || 2011-11-04 || 3679 || 문서 || 3234.23 || 2011-11-05 || 2134234 || 입니다. || 3234.23 || 2011-11-06 || 경로 : C:/abc.xls 첫번째 sheet 읽음 그냥숫자 || 그냥문자 || 아무거나 || 날짜 || 332492 || 안녕하세요 || 3234.23 || 2011-10-30 || 23422 || 가리사니 || 3234.23 || 2011-10-31 || 234234 || 개발자 || 3234.23 || 2011-11-01 || 234234 || 공간 || 3234.23 || 2011-11-02 || 234234 || 입니다. || 3234.23 || 2011-11-03 || 234111 || 테스트 || 3234.23 || 2011-11-04 || 3679 || 문서 || 3234.23 || 2011-11-05 || 2134234 || 입니다. || 3234.23 || 2011-11-06 ||

결론

찜찜한 팁이지만… 조금이라도 도움이 되셨으면 합니다.!!