JAVA 百萬級數據導出

關注要點 

  1. 使用SXSSFWorkbook 專門處理大數據,對於大型excel的創建且不會內存溢出的。它的原理很簡單,用硬盤空間換內存(就像hashmap用空間換時間一樣)。 SXSSFWorkbook是streaming版本的XSSFWorkbook,它只會保存最新的excel rows在內存裏供查看,在此之前的excel rows都會被寫入到硬盤裏(Windows電腦的話,是寫入到C盤根目錄下的temp文件夾)。
  2. 使用excel分頁技術,假設如果有500w條數據,一下導入一個excel的sheet頁中,想想打開excel也需要一段時間吧,慢的話有可能導致程序無法加載,或者直接結束進程的情況。
  3. 爲了防止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;
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章