이전 포스트 했던 excel 관련해 발생한 문제가 있어 정리 해보려고 한다.
문제는 특정 엑셀 파일의 경우, 파일을 열다가 java.lang.OutOfMemoryError: Java heap space 문제가 발생했다.
나는 apache tomcat에 jsp를 이용한 간단한 파일 업로드/다운로드 페이지를 만들어 놓은 것이였는데
서버에 엑셀파일을 올린뒤, 해당 엑셀 파일을 읽는 와중에 오류가 난것이였다.
초보 개발자 답게, 원인보다는 에러메세지에 집중해 먼저 실행되는 java 파일의 vm을 변경해 주었다.
이제 되겠지? 하고 돌렸으나 역시 동일한 문제가 발생했고,
역시 초보 개발자 답게, 다음 스텝으로
eclipse.ini를 건드려 준다.
좋아! 이젠 진짜 되겠지? :) 하고 돌렸으나 역시 동일한 문제가 발생했다.
답이 없을까?
(타부서에게 얘기해 이 엑셀은 메모리문제가 발생하니 해로운 엑셀이다. 라고 말할수 밖에 없는것이다.)
에러가 나는 지점은 여기 였다.
저 부분에 대해 찾아보니
나와 동일한 문제로 골머리를 썪는 개발자 역시 스택오버플로우에 존재하고 있었고,
답변 역시
첫번째 답변에 대해선 해봤으나 안됐으니 두번째 답변을 볼 차례이다.
XSSF + Sax를 이용해 reading 하는 방법이 있다고 나와있다.
XSSF가 문제가 많네... (다 안읽음)
그래서 XSSF+Sax 방법은 어디있는가 구글링....
그래서 찾았다.
/**
* <pre>
* 출처 : https://javavoa-mok.tistory.com/58
* </pre>
*
* @author hermeswing
*/
public class ExcelSheetHandler implements SheetContentsHandler {
private int currentCol = -1;
private int currRowNum = 0;
String filePath = "";
private List<List<String>> rows = new ArrayList<List<String>>(); //실제 엑셀을 파싱해서 담아지는 데이터
private List<String> row = new ArrayList<String>();
private List<String> header = new ArrayList<String>();
public static ExcelSheetHandler readExcel( File file ) throws Exception {
ExcelSheetHandler sheetHandler = new ExcelSheetHandler();
try {
//org.apache.poi.openxml4j.opc.OPCPackage
OPCPackage opc = OPCPackage.open( file );
//org.apache.poi.xssf.eventusermodel.XSSFReader
XSSFReader xssfReader = new XSSFReader( opc );
//org.apache.poi.xssf.model.StylesTable
StylesTable styles = xssfReader.getStylesTable();
//org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable( opc );
//엑셀의 시트를 하나만 가져오기입니다.
//여러개일경우 while문으로 추출하셔야 됩니다.
InputStream inputStream = xssfReader.getSheetsData().next();
//org.xml.sax.InputSource
InputSource inputSource = new InputSource( inputStream );
//org.xml.sax.Contenthandler
ContentHandler handle = new XSSFSheetXMLHandler( styles, strings, sheetHandler, false );
XMLReader xmlReader = SAXHelper.newXMLReader();
xmlReader.setContentHandler( handle );
xmlReader.parse( inputSource );
inputStream.close();
opc.close();
} catch ( Exception e ) {
//에러 발생했을때 하시고 싶은 TO-DO
}
return sheetHandler;
}//readExcel - end
public List<List<String>> getRows() {
return rows;
}
@Override
public void startRow( int arg0 ) {
this.currentCol = -1;
this.currRowNum = arg0;
}
@Override
public void cell( String columnName, String value, XSSFComment var3 ) {
int iCol = ( new CellReference( columnName ) ).getCol();
int emptyCol = iCol - currentCol - 1;
for ( int i = 0; i < emptyCol; i++ ) {
row.add( "" );
}
currentCol = iCol;
row.add( value );
}
@Override
public void headerFooter( String arg0, boolean arg1, String arg2 ) {
//사용안합니다.
}
@Override
public void endRow( int rowNum ) {
if ( rowNum == 0 ) {
header = new ArrayList( row );
} else {
if ( row.size() < header.size() ) {
for ( int i = row.size(); i < header.size(); i++ ) {
row.add( "" );
}
}
rows.add( new ArrayList( row ) );
}
row.clear();
}
public void hyperlinkCell( String arg0, String arg1, String arg2, String arg3, XSSFComment arg4 ) {
// TODO Auto-generated method stub
}
}
// 엑셀 데이터 양식 example
/* A열 B열
1행 test@naver.com Seoul
2행 mouse@gmail.com Busan
3행 apple@daum.net Jeju
*/
//해당 파일은 업로드파일
String filePath = "test.xlsx";
File file = new File(filePath);
ExcelSheetHandler excelSheetHandler = ExcelSheetHandler.readExcel(file);
List<List<String>> excelDatas = excelSheetHandler.getRows();
//excelDatas >>>>> [[ test@naver.com, Seoul ],[ mouse@gmail.com, Busan ], [ apple@daum.net, Jeju ]]
for(List<String> dataRow : excelDatas){
for(String str : dataRow){ // row 하나를 읽어온다.
System.out.println(str); // cell 하나를 읽어온다.
}
}
가져온 엑셀을 읽을 경우 애로사항이 하나 있는데 병합된 셀의 경우 빈칸으로 읽는 다는 점이다.
내 경우, columns 별로만(세로 로만) 병합이 이루어지는 파일이 였기 때문에 이전 값을 기억했다가
특정 셀일 경우 + 빈칸인 경우 -> 이전 값을 가져와 그대로 사용하는 로직으로 구현했다.
이방법으로 크기가 큰 엑셀을 읽을 수 있음은 물론
기존 병합셀+기존셀 읽는 시간이 엄청 줄어든것을 확인했다.
미래의 내가 동일한 삽질 하지 않기를 바라며 기록한다.
'text > Java' 카테고리의 다른 글
java ArrayList source code 살펴보기 (1) | 2022.09.20 |
---|---|
Garbage collection 이 무엇인가요? 왜 쓰나요? 어떤 문제가 있을까요? (0) | 2022.08.01 |
로그인 로직 구현해보기 (jsp, java, tomcat) (5) | 2022.01.15 |
log4j2 executable jar에 적용하기 (0) | 2021.10.17 |
java excel 처리 정리 (0) | 2021.04.16 |
댓글