JAVA大數據導出EXCEL方案

前言

Java當中經常使用的Excel文檔導出主要有POI、JXL和「直接IO流」這三種方式,三種方式各自分別有不一樣的優點與缺點,下面將分行對其進行單介紹。java

導出經常使用文件格式

1. Excel2003格式數據庫

Excel2003支持每一個工做表中最多有 65536 行和 256列。對於工做表可以支持的最大個數,受CPU反應速度和內存大小影響。採用經常使用導出方式導出數據時,須要注意的是Excel 2003行數和列數的限制。經常使用導出方式中的POI支持該格式的只有HSSF包,當導出數據量大於一頁的最大行數(65536)時,可採起分頁的形式進行存儲。app

經常使用導出方式推薦: 1)POI
2)JXL
編輯器

對於推薦的導出方式對Excel 2003的支持,都對最大導出數據量作了限制,不能實現百萬級大數據量的導出。工具

2. Excel2007格式字體

Excel 2007是Excel 2003的升級版,Excel 2007支持每一個工做表中最多有 1,048,576 行和 16,384 列。採用經常使用導出方式導出數據時,須要注意的是Excel 2007行數和列數的限制,經常使用導出方式支持該格式的只有XSSF包,包含SXSSF擴展包,而且僅有SXSSF支持大數據。大數據

經常使用導出方式推薦: 1)POI3.8版本以上。spa

3. CSV格式excel

CSV是一種通用的、相對簡單的文件格式,普遍的應用在程序之間轉移表格數據。code

它一般具備如下特徵:
1)純文本,可使用Excel和文本編輯器打開;
2)每條記錄被分隔符分隔爲字段(典型分隔符有逗號、分號或製表符;有時分隔符可 以包括可選的空格);
3)經常使用導出方式不會引發內存溢出問題。

經常使用導出方式推薦:1)直接IO流。

導出方案

1、使用Apache POI SXSSFWorkbook方式進行導出Excel。

方案簡介

Apache POI 是用Java編寫的免費開源的跨平臺的 Java API,Apache POI提供API給Java程式對Microsoft Office格式檔案讀和寫的功能。
Apache的POI組件是Java操做Microsoft Office辦公套件的強大API,因爲Office 2007的文件結構徹底不一樣於2003,POI有不一樣的處理API,當導出格式爲Office 2003時POI調用的是HSSF包,當導出格式爲Office 2007時,則調用XSSF包,而SXSSF包是POI3.8版本之上對XSSF的一個擴展,用於大數據量的導出,實際應用中可有效避免內存溢出的問題。

此方式對不只支持對Excel的操做,也支持對Microsoft Office其餘格式檔案的操做,如:Word、PowerPoint等,支持單元格的複雜操做,而且該方式在讀取效率上遠遠優於JXL方式,在數據處理量級上也遠非JXL方式可比。

推薦使用狀況:
1)大數據;
2)複雜的單元格要求;
3)讀取數據時。
具體使用調用POI何種包來實現導出功能,須要視需求而定。

代碼實現

public void exportExcle() {
	//設置存儲在內存的行數,多餘的存儲在硬盤
	int cacheItems = 100;
	Workbook wb = new SXSSFWorkbook(cacheItems);
	Sheet sh = wb.createSheet();
	ResultSet rs = queryData();//查詢數據
	int rownum = 0;
	while(rs.next()){
		Row row = sh.createRow(rownum);
		Cell cell = row.createCell(0);
		cell.setCellValue(rs.getString("c1"));
		cell = row.createCell(1);
		cell.setCellValue(rs.getString("c2"));
		…
		cell = row.createCell(19);
		cell.setCellValue(rs.getString("c20"));
		rownum ++;
		//每當行數達到設置的值就刷新數據到硬盤,以清理內存
		if(rownum % cacheItems == 0){
		    ((SXSSFSheet)sh).flushRows();
		}
	}
	JdbcUtil.closeJdbc(rs);
	FileOutputStream out = new FileOutputStream("/excel_data.xlsx");
	wb.write(out);
	out.close();
}
複製代碼

2、使用緩衝流生產csv格式文件

方案簡介

流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱爲流,流的本質是數據傳輸,根據數據傳輸特性將流抽象爲各類類,方便更直觀的進行數據操做。而上面提到的POI和JXL實際都是基於IO流封裝的工具。
該方式採用最原始的形式進行導出工做,選擇合適的流工做效率會很是出色。

可是僅支持對文本文件的操做,如:CSV、TXT等,且導出的文件會相對較大。


推薦使用狀況:1)導出文件格式爲文本文件;2)不在乎導出的文件過大。

本文將分別採用上述三種方式實現大數據量導出功能,從不一樣方面(數量級、導出時間、佔用存儲空間)反應其優劣性,以供開發人員作出最合理的選擇。

代碼實現

public void exportExcle() {
	File csvFile = null;
	BufferedWriter csvWriter = null;
	csvFile = new File("/excel_data.csv");
	File parent = csvFile.getParentFile();
	if (parent != null && !parent.exists()) {
	    parent.mkdirs();
	}
	csvFile.createNewFile();

	// UTF-8使正確讀取分隔符","
	csvWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
	        csvFile), "UTF-8"), 1024);

	ResultSet rs = queryData();//查詢數據
	while(rs.next()){
		StringBuffer sb = new StringBuffer();
		sb.append("\"").append(rs.getString("c1")).append("\";");
		sb.append("\"").append(rs.getString("c2")).append("\";");
        …
		sb.append("\"").append(rs.getString("20")).append("\"");
		csvWriter.write(sb.toString());
		csvWriter.newLine();
	}
	csvWriter.close();
}

複製代碼

3、使用JXL方式導出EXCEL。

方案簡介

JXL是一個開源的Java Excel API項目。它能做爲Java Excel API的一個共同的支持庫,是由於它的基本功能是可建立,讀取和寫入電子表格。基本特徵以下:
1)生成Excel文件
2)從工做簿和電子表格導入數據
3)得到行和列的總數

此方式對中文支持很好,不會出現亂碼狀況,支持單元格的經常使用操做,知足通常需求,該方式在寫入效率上優於POI方式。

可是須要注意:JXL只支持xls檔案格式,而且處理的數據量很是有限。

推薦使用狀況:1)數據量不是太大;2)單元格要求簡單;3)寫入數據時。

代碼實現

public void exportExcle() {
	WorkbookSettings wbSetting = new WorkbookSettings();
    wbSetting.setUseTemporaryFileDuringWrite(true);
    wbSetting.setTemporaryFileDuringWriteDirectory(new File("/"));//臨時文件夾的位置
    WritableWorkbook book = jxl.Workbook.createWorkbook(new File("/excel_data.xls"),wbSetting);

    //設置樣式,字體
    WritableFont font1 = new WritableFont(WritableFont.createFont("微軟雅黑"), 10 ,WritableFont.BOLD);
    WritableFont font2 = new WritableFont(WritableFont.createFont("微軟雅黑"), 9 ,WritableFont.NO_BOLD);
    WritableCellFormat wcf = new WritableCellFormat(font1);
    WritableCellFormat wcf2 = new WritableCellFormat(font2);

    //平行居中
    wcf.setAlignment(Alignment.CENTRE);
    //垂直居中
    wcf.setVerticalAlignment(VerticalAlignment.CENTRE);
    wcf2.setAlignment(Alignment.CENTRE);
    wcf2.setVerticalAlignment(VerticalAlignment.CENTRE);
    
    ResultSet rs = queryData();//查詢數據
	int rownum = 0;
	//SHEET頁大小,最大不超過65536
	int sheetCount = 50000;
	int sheetNum = 0;
	WritableSheet sheet = null;
	while(rs.next()){
		if(rownum % sheetCount == 0){
			sheetNum ++;
			rownum = 0;
			//生成名爲「第一頁」的工做表,參數0表示這是第一頁
			sheet = book.createSheet( "第"+ sheetNum +"頁 " , sheetNum - 1);
		}
        //頁設置對象
        sheet.addCell(new Label( 0 , rownum, rs.getString("c1"), wcf2));
        sheet.addCell(new Label( 1 , rownum, rs.getString("c2"), wcf2));
        ...
        sheet.addCell(new Label( 18 , rownum, rs.getString("c19"), wcf2));
        sheet.addCell(new Label( 19 , rownum, rs.getString("c20"), wcf2));
        //設置行高
        sheet.setRowView(rownum, 370);
        rownum ++;
	}

	//寫入數據並關閉文件
	book.write();
	
    book.close();
}
複製代碼

總結

對於以上三種解決大數據量導出的方案,因爲第三種解決方案限制了可以導出的最大數據量,故此不做推薦。
方案一和方案二對於大數據量的導出具備很好的支持,可見於對導出格式、佔用的存儲空間等要素來選擇更適合的方案。
須要特別注意的是,兩種方案都涉及到從數據庫提取數據裝載到List時容易引起內存溢出的狀況,請妥善處理。


喜歡能夠關注公衆號: 終身幼稚園

相關文章
相關標籤/搜索