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流。
方案簡介
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();
}
複製代碼
方案簡介
流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱爲流,流的本質是數據傳輸,根據數據傳輸特性將流抽象爲各類類,方便更直觀的進行數據操做。而上面提到的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();
}
複製代碼
方案簡介
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時容易引起內存溢出的狀況,請妥善處理。
喜歡能夠關注公衆號: 終身幼稚園