대용량 Excel 파일 쓰기(50w+ 지원) (2)

12003 단어 Java 기반

대용량 Excel 파일 쓰기(50w+ 지원)


1 온라인 메모리 넘침 문제 프레젠테이션


환경 준비
jvm 실행 매개 변수 설정은 다음과 같습니다. -Xms100M -Xmx100M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d://dump.hprof예제 코드
/**
 *  excel 
 *
 * @author Leon
 * @date 2020-05-06 11:23
 */
public class WriteExcelDemo
{

	public static void main(String[] args) throws Exception
	{
		XSSFWorkbook wb = new XSSFWorkbook();
		XSSFSheet sheet = wb.createSheet("sheet-test");

		//  50 
		for (int i = 0; i < 500000; i++)
		{
			XSSFRow curRow = sheet.createRow(i);
			XSSFCell cell = curRow.createCell(0);
			cell.setCellValue(LocalDate.now().toString());
		}

		FileOutputStream fos = new FileOutputStream("d:\\test111.xlsx");
		wb.write(fos);
		fos.close();
	}
}

실행 결과
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to d://dump.hprof ...
Heap dump file created [163701970 bytes in 0.973 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at org.apache.xmlbeans.impl.store.Xobj.ensureParent(Xobj.java:614)
	at org.apache.xmlbeans.impl.store.Xobj.getNormal(Xobj.java:661)
	at org.apache.xmlbeans.impl.store.Cur.getNormal(Cur.java:2464)
	at org.apache.xmlbeans.impl.store.Cur.skip(Cur.java:1269)
	at org.apache.xmlbeans.impl.store.Cur.moveNode(Cur.java:1840)
	at org.apache.xmlbeans.impl.store.Cur.createHelper(Cur.java:287)
	at org.apache.xmlbeans.impl.store.Cur.createElement(Cur.java:231)
	at org.apache.xmlbeans.impl.store.Cur.createElement(Cur.java:226)
	at org.apache.xmlbeans.impl.store.Xobj.insertElement(Xobj.java:2116)
	at org.apache.xmlbeans.impl.store.Xobj.add_element_user(Xobj.java:2197)
	at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl.addNewC(Unknown Source)
	at org.apache.poi.xssf.usermodel.XSSFRow.createCell(XSSFRow.java:220)
	at org.apache.poi.xssf.usermodel.XSSFRow.createCell(XSSFRow.java:198)
	at com.concurrent.excel.WriteExcelDemo.main(WriteExcelDemo.java:35)


우리는 메모리가 넘치는 것을 발견했다.

2 작은 메모리로 초대형 excel 데이터 쓰기


지난 소절에서 우리는 OOM 현상과 원인을 설명했고 이런 상황에 대해 POI 정부도 해결 방안을 제시했다.바로 SXSSF.
POI는 SXSSF의 방식으로 매우 큰 xlsx 파일을 유동적으로 만들 수 있습니다. SXSSF는 윈도우의 개념을 사용합니다. 데이터 줄이 윈도우의 범위를 초과하면 내용을 수정할 수 없습니다.
이 창의 크기는 구조 함수 new SXSSFWorkbook(int windowSize) 나 sheet SXSSFSheet#setRandomAccessWindowSize(int windowSize) 에서 설정할 수 있으며, 기본값은 SXSSFWorkbook.DEFAULT_WINDOW_SIZE(100) 입니다.
또한 SXSSF는 임시 파일을 만들 수 있습니다. 이것은finally에서 디스플레이를 사용하여 디스포지션을 호출하여 제거해야 합니다. 또한 임시 파일도 일정한 하드디스크를 사용합니다. wb.setCompressTempFiles(true) 워크북의 임시 파일을 설정하여 압축을 사용하여 하드디스크의 사용을 줄일 수 있습니다.
예는 다음과 같다.
예제 코드
이 코드는 생산 환경에 직접 사용할 수 있습니다.

/**
 *  excel 
 *
 * @author Leon
 * @date 2020-05-06 11:23
 */
public class SxssfWriteExcelDemo
{

	public static void main(String[] args) throws Exception
	{
		// jvm : -Xms100M -Xmx100M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d://dump.hprof
		SXSSFWorkbook wb = new SXSSFWorkbook();

		try
		{
			Sheet sheet = wb.createSheet();

			//  100 
			for (int i = 0; i < 1000000; i++)
			{
				Row curRow = sheet.createRow(i);
				Cell cell = curRow.createCell(0);
				cell.setCellValue(LocalDate.now().toString() + UUID.randomUUID().toString() + new Random().nextInt());
			}

			FileOutputStream fos = new FileOutputStream("d:\\test111.xlsx");
			wb.write(fos);
			fos.close();
		}
		finally
		{
			//  
			if( wb != null)
			{
				wb.dispose();
			}
		}

		System.out.println("ok");
	}
}


실행 결과
100w개의 데이터를 성공적으로 썼고 어떠한 오류도 보고하지 않았습니다.

3 매듭


SXSSF는 큰 파일을 쓰는 문제를 해결할 수 있지만 파일의 원래 내용을 수정할 수 없고 원본 파일을 읽을 수도 없습니다.
필요한 경우 이전에 읽은 큰 파일과 결합하여 읽은 내용을 SXSSF를 통해 새 파일에 작성하여 유사한 수정 작업을 수행할 수 있습니다.

좋은 웹페이지 즐겨찾기