Java 使用POI 匯出 百萬級別的資料量的 Excel
阿新 • • 發佈:2019-02-15
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