1. 程式人生 > >Java 使用POI 匯出 百萬級別的資料量的 Excel

Java 使用POI 匯出 百萬級別的資料量的 Excel

1.首先介紹一下目前匯出excel的幾種格式:Excel 2003、Excel 2007

 Excel 2003:POI中使用HSSF物件時,excel 2003最多只允許儲存65536條資料,一般用來處理較少的資料量。這時對於百萬級別資料,Excel肯定容納不了。

 Excel 2007:當POI升級到XSSF物件時,它可以直接支援excel2007以上版本,因為它採用ooxml格式。這時excel可以支援1048576條資料,單個sheet表就支援近104萬條資料了,雖然這時匯出100萬資料能滿足要求,但使用XSSF測試後發現偶爾還是會發生堆溢位,所以也不適合百萬資料的匯出。

在POI3.8之後新增加了一個類,SXSSFWorkbook,採用當資料加工時不是類似前面版本的物件,

它可以控制excel資料佔用的記憶體,他通過控制在記憶體中的行數來實現資源管理,即當建立物件超過了設定的行數,

它會自動重新整理記憶體,將資料寫入檔案,這樣導致列印時,佔用的CPU,和記憶體很少。

所以本文將使用SXXFWorkBook來實現百萬級別資料量的匯出。

2.下面是Java 程式碼部分

import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 
/**
 * @Description: 處理百萬級別的excel匯出操作工具類
 * @author : hujingbo
 * @date : 2017-9-22 下午1:55:31
 */
public class BigDataExcelOutWrite {
	/**
	 * 資料庫連線操作
	 * 
	 * @throws Exception
	 */
	public Connection getConnection() throws Exception {
 
		// 使用jdbc連結資料庫
		Class.forName("com.mysql.jdbc.Driver").newInstance();
		String url = "jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8";
		String username = "root";
		String password = "123456";
 
		// 獲取資料庫連線
		Connection conn = DriverManager.getConnection(url, username, password);
		return conn;
	}
 
	/**
	 * 
	 * @Title: WriteExcel
	 * @Description: 執行匯出Excel操作
	 * @param
	 * @return boolean
	 * @throws
	 */
	public boolean WriteExcel(boolean isClose) {
 
		String excelFile = "D:/bigData.xlsx";
		// 記憶體中只建立100個物件,寫臨時檔案,當超過100條,就將記憶體中不用的物件釋放。
		SXSSFWorkbook wb = new SXSSFWorkbook(100);
		Sheet sheet = null; // 工作表物件
		Row nRow = null; // 行物件
		Cell nCell = null; // 列物件
 
		try {
 
			Connection conn = getConnection();
			Statement stmt = conn.createStatement();
			String sql = "select * from hpa_normal_tissue limit 1000000";
			ResultSet rs = stmt.executeQuery(sql); // 獲取執行結果
			ResultSetMetaData rsmd = rs.getMetaData(); // 獲取執行結果的結構(rs.getMetaData().getTableName(1))就可以返回表名,rs.getMetaData().getColumnCount())
 
			long startTime = System.currentTimeMillis();
			System.out.println("開始執行時間 : " + startTime / 1000 + "m");
			int rowNo = 0; // 總行號
			int pageRowNo = 0; // 頁行號
 
			while (rs.next()) {
				// 列印300000條後切換到下個工作表,可根據需要自行拓展,2百萬,3百萬...資料一樣操作,只要不超過1048576就可以
				if (rowNo % 300000 == 0) {
					System.out.println("當前sheet頁為:" + rowNo / 300000 );
					sheet = wb.createSheet("我的第" + (rowNo / 300000 + 1) + "個工作簿");// 建立新的sheet物件
					sheet = wb.getSheetAt(rowNo / 300000); // 動態指定當前的工作表
					pageRowNo = 1; // 每當新建了工作表就將當前工作表的行號重置為1
					
				    //定義表頭
				    nRow = sheet.createRow(0);
				    Cell cel0 = nRow.createCell(0);  
				    cel0.setCellValue("第一行");
				    Cell cel2 = nRow.createCell(1);  
				    cel2.setCellValue("第二行");  
				    Cell cel3 = nRow.createCell(2);  
				    cel3.setCellValue("第三行");  
				    Cell cel4 = nRow.createCell(3); 
				    cel4.setCellValue("第四行");
				    Cell cel5 = nRow.createCell(4); 
				    cel5.setCellValue("第五行");
				    Cell cel6 = nRow.createCell(5); 
				    cel6.setCellValue("第六行");
				}
				rowNo++;
				nRow = sheet.createRow(pageRowNo++); // 新建行物件
 
				// 列印每行,每行有6列資料 rsmd.getColumnCount()==6 --- 列屬性的個數
				for (int i = 0; i < rsmd.getColumnCount(); i++) {
					nCell = nRow.createCell(i);
					nCell.setCellValue(rs.getString(i + 1));
				}
 
				if (rowNo % 10000 == 0) {
					System.out.println("row no: " + rowNo);
				}
			}
 
			long finishedTime = System.currentTimeMillis(); // 處理完成時間
			System.out.println("資料讀取完成耗時 : " + (finishedTime - startTime) / 1000 + "m");
			
			FileOutputStream fOut = new FileOutputStream(excelFile);//將資料寫入Excel
			wb.write(fOut);
			fOut.flush(); // 重新整理緩衝區
			fOut.close();
 
			long stopTime = System.currentTimeMillis(); // 寫檔案時間
			System.out.println("資料寫入Excel表格中耗時 : " + (stopTime - startTime) / 1000 + "m");
 
			if (isClose) {
				this.close(rs, stmt, conn);
			}
 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
 
	// 執行關閉流的操作
	private void close(ResultSet rs, Statement stmt, Connection conn)throws SQLException {
		rs.close();
		stmt.close();
		conn.close();
	}
	//測試方法
	public static void main(String[] args) {
		BigDataExcelOutWrite bdeo = new BigDataExcelOutWrite();
		bdeo.WriteExcel(true);
	}
}

執行之後的效果圖

3.所需的sql檔案和相關的jar包。

連結: https://pan.baidu.com/s/1nvOJgWL    密碼: eqj9