일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- ^M바꾸기
- maven
- driverspy
- duplicate lines
- Change port
- JAR
- mariadb
- object
- jdbc
- Jenkins
- change file content
- spring
- install maven
- remove
- 줄복사
- pkgutil
- spring boot
- ubuntu
- Java
- JavaScript
- gradle
- svn backup
- install
- 전송포맷
- not to accept jdbcUrl
- docker
- key bindings
- ADB
- javaascript
- local
- Today
- Total
Simplify
자바 프로그래밍으로 엑셀 파일 읽기 - How to read Excel file with Java programming (with POI) 본문
자바 프로그래밍으로 엑셀 파일 읽기 - How to read Excel file with Java programming (with POI)
Simplify - Jonghun 2020. 2. 24. 16:27서버 측 프로그래밍을 하다 보면, 특히나 웹 프로그래밍을 하다보면, Excel 파일을 읽고 쓰는 일이 빈번합니다. 예를 들어 화면에 출력된 내용을 Excel 파일로 내보내기(export)한다거나, 한꺼번에 다량의 항목을 등록하려 할 때에 Excel 파일로 등록하기(import) 등의 기능이 이에 해당합니다. 물론 다양한 방법으로 Excel 파일을 읽고 쓰는 것이 가능하지만, 가장 흔히 사용되고 편리한 것은 POI 라는 것을 이용하는 것입니다. 사실 과거에 - 아주 오래전 - 는 엑셀 파일을 테스트 파일로 읽어들이면, xml 파일과 유사한 형태를 띄고 있어 쉽게 읽고 쓰는 것이 가능했지만, 최근에는 보안상의 이유인지 이 마저도 제대로 보이지 않고, 특히 xlsx 파일은 똑바로 읽을 방법이 없습니다.
간단하지만 가볍게 봐 두면 한번 쯤은 사용하게 되는 기능인 것 같습니다. 코드부터 보여드리고 몇 가지 팁을 적겠습니다.
package excel;
import java.io.FileInputStream;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExcelRead {
public static void main(String[] args) {
try {
FileInputStream file = new FileInputStream("D:/tmp/upload/right_excel/test.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(file);
int rowindex=0;
int columnindex=0;
//시트 수 (첫번째에만 존재하므로 0을 준다)
//만약 각 시트를 읽기위해서는 FOR문을 한번더 돌려준다
XSSFSheet sheet=workbook.getSheetAt(0);
//행의 수
int rows=sheet.getPhysicalNumberOfRows();
for(rowindex=0;rowindex<rows;rowindex++){
//행을읽는다
XSSFRow row=sheet.getRow(rowindex);
if(row !=null){
//셀의 수
int cells=row.getPhysicalNumberOfCells();
for(columnindex=0; columnindex<=cells; columnindex++){
//셀값을 읽는다
XSSFCell cell=row.getCell(columnindex);
String value="";
//셀이 빈값일경우를 위한 널체크
if(cell==null){
continue;
}else{
//타입별로 내용 읽기
switch (cell.getCellType()){
case XSSFCell.CELL_TYPE_FORMULA:
value=cell.getCellFormula();
break;
case XSSFCell.CELL_TYPE_NUMERIC:
value=cell.getNumericCellValue()+"";
break;
case XSSFCell.CELL_TYPE_STRING:
value=cell.getStringCellValue()+"";
break;
case XSSFCell.CELL_TYPE_BLANK:
value=cell.getBooleanCellValue()+"";
break;
case XSSFCell.CELL_TYPE_ERROR:
value=cell.getErrorCellValue()+"";
break;
}
}
System.out.println(rowindex+"번 행 : "+columnindex+"번 열 값은: "+value);
}
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
편의 상, 아래 출처& 참고자료에 적힌 블로그에서 코드 블럭을 가져왔습니다. 저 역시 유사하게 사용하있고 간단한 것들은 이 정도로 충분합니다만, 다음과 같은 부분에 대해서 추가적으로 팁을 드리고자 합니다.
xls * xlsx 파일 두 가지 모두 처리하기
FileInputStream fileInputStream = new FileInputStream(templateFile);
if (templateFile.getAbsolutePath().endsWith("xlsx")) {
workbook = new XSSFWorkbook(fileInputStream);
} else if (templateFile.getAbsolutePath().endsWith("xls")) {
workbook = new HSSFWorkbook(fileInputStream);
}
파일 확장자에 따라서 분기합니다. 이렇게 하면 위 소스에서 몇 가지 부분이 에러가 발생할 텐데, 그 상위 클래스로 잡하주면 됩니다. 예를 들어 XSSFCell 은 그냥 Cell 로 잡아주면 되고, Cell Type을 분기하는 부분은 아래와 같이 분기하면 됩니다.
switch (cell.getCellType()) {
case FORMULA:
...
첫 줄이 비어있는, 중간부터 쓰여있는 표 형태를 읽는 경우
int lastRowIndex = sheet.getLastRowNum();
for (rowIndex = 0; rowIndex <= lastRowIndex; rowIndex++) {
int realRowIndex = rowIndex + sheet.getFirstRowNum();
Row row = sheet.getRow(realRowIndex);
...
위와 같은 형태로 처리하면 중간에 덩그러니 쓰여있는 형태의 파일도 제대로 읽어올 수 있습니다.
getLastRowNum() 함수는 그야말로 유효한 값이 있는 마지막 행 번호를 받아옵니다. 그런데, 0번 Row 부터 처리하면 빈 row 가 나올 수 있기 때문에 첫 줄은 getFirstRowNum() 으로 가져오는 것이 맞습니다. 이렇게 하면 빈줄 읽어와서 처리하는 것 대신에, 유효한 첫 줄부터 유효한 마지막 줄 까지를 읽을 수 있습니다.
셀 읽는 범위 처리
위와 같이 getPhysicalNumberOfCells() 를 호출해서 얻는 숫자는 유효한 컬럼 수를 return 합니다. 만얀 A, B 컬럼 정도가 비어있다면, 위 형태로는 마지막까지 읽지 못하고 마지막 두 컬럼을 읽지 못합니다. 따라서 아래와 같이 처리합니다.
nt lastCellIndex = row.getLastCellNum();
for (columnIndex = 0; columnIndex <= lastCellIndex; columnIndex++) {
Cell cell = row.getCell(columnIndex);
Object value = null;
if (cell != null) {
...
마지막 cell 번호를 getLastCellNum() 으로 얻어옵니다. 이렇게 하면 유효한 값이 있는 마지막 셀을 얻어오므로, 0번 컬럼부터 체크하면서 null 여부를 판단하면 마지막 셀 까지 다 읽어낼 수 있습니다.
여러가지 트릭이나 편법이 있고, 더 좋은 방법들이 있는 줄 알고 있습니다만, 위에서 설명한 세 가지는 유용한 정보로 보여 공유 차원에서 올립니다. 적고 나니 getFirstCellNum() 이 있는지 궁금하네요. (아마 있을 듯 싶습니다..)
엑셀을 읽을 때 정해진 틀 내에서 처리하도록 가이드하는 것도 중요하므로 보통 '다량 건 일괄 등록'과 같은 기능을 개발하는 경우에는 templete 파일을 제공하고 이 틀에 맞추어 등록하도록 가이드합니다.
그래도 혹시 모르고, 조금 더 자유롭게 등록하게 하기 위해서, 또 다양한 파이를 그대로 읽기 위해서는 위와 같이 작업해 두는 것이 좋습니다.