import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/***
* POI 多線程多sheet導出數據
*/
public class ThreadExcelUtils {
/**
* 定義每個 sheet 最多數量
*/
public static final Integer EXCEL_MAX_CNT = 50000;
private Workbook wb;
private String fileName;
private String filePath;
private String[] hearders;
private String[] fields;
public Workbook getWb() {
return wb;
}
public String getFileName() {
return fileName;
}
public String getFilePath() {
return filePath;
}
public String[] getHearders() {
return hearders;
}
public String[] getFields() {
return fields;
}
/**
* @param fileName
* 文件名稱
* @param filePath
* 文件路徑
* @param hearders
* 文件頭
* @param fields
* 字段屬性
*/
public ThreadExcelUtils(String fileName, String filePath,
String[] hearders, String[] fields) {
this.wb = new HSSFWorkbook();
this.fileName = fileName;
this.filePath = filePath;
this.hearders = hearders;
this.fields = fields;
}
public static void main(String[] args) throws Exception {
List<Map<String, Object>> lists = new ArrayList<Map<String, Object>>();
// 造數據
for (int i = 0; i < 10000; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name1", "張三" + i);
map.put("name2", "李四" + i);
map.put("name3", "王五" + i);
lists.add(map);
}
String[] header = { "姓名1", "姓名2", "姓名3" };
String[] fileNames = { "name1", "name2", "name3" };
String filePath = "D:\\excelFile";
String filename = "測試表 " + getDate(new Date()) + ".xls";
ThreadExcelUtils utils = new ThreadExcelUtils(filename, filePath,
header, fileNames);
System.out.println("開始執行導出.......");
long start = System.currentTimeMillis();
utils.exportExcelToFilePath(lists);
long end = System.currentTimeMillis();
System.out.println("耗時:" + (end - start) / 1000 + "秒");
}
/**
* @param list
* 數據
*/
public void exportExcelToFilePath(List<Map<String, Object>> list)
throws Exception {
int excelSize = EXCEL_MAX_CNT; // 每個Excel文件條數
int totalCount = list.size(); // 查詢結果總條數
int pageCount = 0;// 總sheet頁個數
int numPage = totalCount % excelSize; // 是否整頁數
if (numPage > 0)
pageCount = totalCount / excelSize + 1;
else
pageCount = totalCount / excelSize;
// 創建線程池 多sheet多線程寫入 線程數 爲sheet頁的 1/4
Integer threadNumber = pageCount / 4;
if (threadNumber == 0)
threadNumber = 1;
ExecutorService threadPool = Executors.newFixedThreadPool(threadNumber);
// 創建柵欄 等待任務完成
CountDownLatch countDownLatch = new CountDownLatch(pageCount);
// 循環遍歷投遞任務
for (int i = 1; i <= pageCount; i++) {
ThraedExcel thraedExcel = new ThraedExcel(list, i, pageCount,
numPage, this);
thraedExcel.setCountDownLatch(countDownLatch);
threadPool.execute(thraedExcel);
}
countDownLatch.await();
Workbook wb = getWb();
File file = new File(filePath);
FileOutputStream fout = new FileOutputStream(new File(file, fileName));
try {
wb.write(fout);
} catch (IOException e) {
e.printStackTrace();
}
// System.out.println("文件寫入完成");
// 立即銷燬線程池
threadPool.shutdownNow();
}
private static String getDate(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
"yyyyMMddHHmmss");
String format = simpleDateFormat.format(date);
return format;
}
/**
* JavaBean轉Map
*
* @param obj
* @return
*/
public static Map<String, Object> beanToMap(Object obj) {
Map<String, Object> params = new HashMap<String, Object>(0);
try {
PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
PropertyDescriptor[] descriptors = propertyUtilsBean
.getPropertyDescriptors(obj);
int length = descriptors.length;
for (int i = 0; i < length; i++) {
String name = descriptors[i].getName();
if (!StringUtils.equals(name, "class")) {
params.put(name, propertyUtilsBean.getNestedProperty(obj,
name));
}
}
} catch (Exception e) {
System.err.println("bean 轉Map出錯");
e.printStackTrace();
}
return params;
}
/***
* 線程寫入sheet
*/
private static class ThraedExcel implements Runnable {
private List<Map<String, Object>> list;// 數據
private Integer sheetNumber;// 當前sheet頁
private Integer totalSheetCount;// 總數據
private int numPage; // 是否整頁數
private Integer excelSize;
private ThreadExcelUtils threadExcelUtils;
// 柵欄對象
private CountDownLatch countDownLatch;
/**
* @param list
* 總數據
* @param sheetNumber
* 當前sheet頁
* @param totalSheetCount
* 總sheet頁
* @param numPage
* 是否整數
*/
public ThraedExcel(List<Map<String, Object>> list, Integer sheetNumber,
Integer totalSheetCount, Integer numPage,
ThreadExcelUtils threadExcelUtils) {
this.list = list;// 總數據
this.sheetNumber = sheetNumber;// 當前sheet頁
this.totalSheetCount = totalSheetCount;// 總sheet頁
this.numPage = numPage;// 是否整除
this.excelSize = ThreadExcelUtils.EXCEL_MAX_CNT;// 沒個sheet最大數量
this.threadExcelUtils = threadExcelUtils;// 當前線程對象
}
public void setCountDownLatch(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
List<Map<String, Object>> sheetList = null;
if (totalSheetCount > 1) {
if (numPage == 0) {
sheetList = list.subList((sheetNumber - 1) * excelSize,
excelSize * sheetNumber);
} else {
if (sheetNumber == totalSheetCount) {
sheetList = list.subList((sheetNumber - 1) * excelSize,
list.size());
} else {
sheetList = list.subList((sheetNumber - 1) * excelSize,
excelSize * (sheetNumber));
}
}
} else
sheetList = list;
// 開始寫入數據
createWorkBook(sheetList);
if (this.countDownLatch != null)
this.countDownLatch.countDown();
}
/***
* 寫出數據
*/
private void createWorkBook(List<Map<String, Object>> sheetList) {
Sheet sheet = null;
Row row = null;
synchronized (ThreadExcelUtils.class) {
String fileName = threadExcelUtils.getFileName();
Workbook wb = threadExcelUtils.getWb();
sheet = wb.createSheet(fileName + "_" + this.sheetNumber);
row = sheet.createRow(0);
}
String[] header = threadExcelUtils.getHearders();
String[] fields = threadExcelUtils.getFields();
// 設置標題
for (int i = 0; i < header.length; i++) {
row.createCell(i).setCellValue(header[i]);
}
// 開始寫入數據
if (sheetList != null && sheetList.size() > 0) {
int dataLength = sheetList.size();
for (int i = 0; i < dataLength; i++) {
if (i == 3 || i == 8 || i == 15) {
sheet.setColumnWidth(i, 20 * 256);
} else {
sheet.setColumnWidth(i, 15 * 256);
}
Row row1 = sheet.createRow(i + 1);
Object obj = sheetList.get(i);
Map<String, Object> map = (obj instanceof Map) ? (Map<String, Object>) obj
: beanToMap(obj);
int length = fields.length;
for (int j = 0; j < length; j++) {
String key = fields[j];
Object value = map.get(key);
if (value != null) {
// 不曉得 此處爲啥有線程安全問題
synchronized (ThreadExcelUtils.class) {
if (value instanceof Date) {
SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd");
String format = sdf.format(value);
row1.createCell(j).setCellValue(format);
} else {
try {
row1.createCell(j).setCellValue(
value.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
}
}
POI 多線程多sheet導出數據
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.