關注要點
- 使用SXSSFWorkbook 專門處理大數據,對於大型excel的創建且不會內存溢出的。它的原理很簡單,用硬盤空間換內存(就像hashmap用空間換時間一樣)。 SXSSFWorkbook是streaming版本的XSSFWorkbook,它只會保存最新的excel rows在內存裏供查看,在此之前的excel rows都會被寫入到硬盤裏(Windows電腦的話,是寫入到C盤根目錄下的temp文件夾)。
- 使用excel分頁技術,假設如果有500w條數據,一下導入一個excel的sheet頁中,想想打開excel也需要一段時間吧,慢的話有可能導致程序無法加載,或者直接結束進程的情況。
- 爲了防止List裝載數據過大造成內存溢出,採取分段獲取數據方式,並在每次向row中加載完數據後對List進行手動回收,並將對象釋放從而避免內存溢出。(如需實現方式請留言)。
/**
* 百萬級數據導出
*/
package XXX.XXX.XXX.XXX.impl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
/**
* @author 紫氣東來
*/
public class XxServiceImpl implements XxService {
private XxDao dao;
private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
private String fileName = df.format(Calendar.getInstance().getTime());
private static String sheetName = "sheet_";
private static final String SUFFIX = ".xlsx";
//private String filePath = "D:" + File.separator + "XXX" + File.separator + "XXX" + File.separator + "XXX" + File.separator + fileName + SUFFIX;
private String filePath = File.separator + "XXX" + File.separator + "XXX" + File.separator + "XXX" + File.separator + fileName + SUFFIX;
public XxServiceImpl() {
}
public void setDao(XxDao dao) {
this.dao = dao;
}
@SuppressWarnings("unchecked")
@Override
public File exportFile() {
long startTime = System.currentTimeMillis();
System.out.println("導出開始時間:"
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
.format(startTime));
File file = null;
List ls = this.dao.queryResult();//獲取數據源
Integer dataCount = ls.size();
if (0 == dataCount) return null;
FileOutputStream out = null;
SXSSFWorkbook workbook = null;
SXSSFSheet sheet = null;
int maxDataSize = 5000;
int sheetCnt = 0;
if (dataCount > maxDataSize) {
if (0 == dataCount / maxDataSize) sheetCnt = dataCount / maxDataSize;
else sheetCnt = dataCount / maxDataSize + 1;
} else sheetCnt = 1;
workbook = new SXSSFWorkbook(100);
workbook.setCompressTempFiles(true);
for (int i = 0; i < sheetCnt; i++) {
sheet = (SXSSFSheet) workbook.createSheet(sheetName + (i + 1));
sheet.setDefaultColumnWidth(25);
SXSSFRow row = null;
setHeader(row, sheet);
Map<String, String> resultMap = new HashMap<String, String>();
int curMaxDataSize = dataCount > (i + 1) * maxDataSize ? (i + 1)
* maxDataSize : dataCount;
int idx = 1;
for (int j = i * maxDataSize; j < curMaxDataSize; j++) {
resultMap = (Map<String, String>) ls.get(j);
row = (SXSSFRow) sheet.createRow(idx ++);
setRow(row, resultMap);
}
resultMap.clear();
resultMap = null;
}
try {
file = createFile(filePath);
out = new FileOutputStream(file);
workbook.write(out);
out.close();
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
} catch (IOException e) {
System.err.println(e.getMessage());
}
long endTime = System.currentTimeMillis();
System.out.println("導出結束時間:"
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
.format(endTime));
System.out.println("當前程序耗時:" + (endTime - startTime) + "ms" + " | 共:"
+ dataCount + "條數據");
return file;
}
private File createFile(String src) throws IOException {
String path = src.substring(0, src.lastIndexOf(File.separator));
String fileName = src.substring(src.lastIndexOf(File.separator) + 1, src.length());
File f = new File(path);
if (!f.exists()) f.mkdirs();
File file = new File(f, fileName);
if (!file.exists()) file.createNewFile();
return file;
}
public void isToFile(InputStream is, File file) throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(file);
int len = 0;
byte[] buffer = new byte[8192];
while ((len = is.read(buffer)) != -1)
os.write(buffer, 0, len);
} finally {
os.close();
is.close();
}
}
private void setHeader(SXSSFRow row, SXSSFSheet sheet) {
row = (SXSSFRow) sheet.createRow(0);
setRow(row, null);
}
private void setRow(SXSSFRow row, Map<String, String> resultMap) {
if (resultMap == null) {
getCell(row, 0).setCellValue("header1");
getCell(row, 1).setCellValue("header2");
getCell(row, 2).setCellValue("header3");
getCell(row, 3).setCellValue("header4");
getCell(row, 4).setCellValue("header5");
} else {
getCell(row, 0).setCellValue(resultMap.get("NAME1"));
getCell(row, 1).setCellValue(resultMap.get("NAME2"));
getCell(row, 2).setCellValue(resultMap.get("NAME3"));
getCell(row, 3).setCellValue(resultMap.get("NAME4"));
getCell(row, 4).setCellValue(resultMap.get("NAME5"));
}
}
private Cell getCell(Row row, int index) {
Cell cell = row.getCell(index);
if (cell == null) cell = row.createCell(index);
return cell;
}
}