欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java 之 导出百万数据到excel

程序员文章站 2022-07-13 15:51:28
...

说明

首先申明,本人不是标题党。使用如下代码测试100w条数据导出到excel文件,单线程使用17s,多线程使用13s。当然,针对类似方法的使用,有人做过测试,比我的还详细。但是具体到个人,建议你使用的时候还是要自己测试一下。

测试链接

依赖

<!-- 依赖,你也可以使用更高版本,但是使用之前看下版本异同 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.8</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.8</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-excelant</artifactId>
    <version>3.8</version>
</dependency>

代码

	public static void main(String[] args) throws IOException {
		FileOutputStream targetFile = new FileOutputStream(new File("d:\\Users\\Desktop\\laji\\Import-device-exampleyy.xlsx"));

//		testSXSSFThreadPool(targetFile, 1000003);
//		testSXSSF(targetFile);
	}

	private static  final int PER_SHEET_LIMIT=50000;	//每页5w
	private static void testSXSSFThreadPool(OutputStream targetFile, int total) throws IOException{
		int pageNum = total / PER_SHEET_LIMIT;
		int lastCount = total % PER_SHEET_LIMIT;
		if (total > PER_SHEET_LIMIT) {
			long start = System.currentTimeMillis();
			SXSSFWorkbook wb = new SXSSFWorkbook();
			int sheet = lastCount == 0 ? pageNum : pageNum + 1;
			CountDownLatch downLatch = new CountDownLatch(sheet);
			Executor executor = Executors.newFixedThreadPool(sheet);
			for (int c = 0; c < sheet; c++) {
				int rowNum = PER_SHEET_LIMIT;
				if (c == pageNum) {
					if (lastCount == 0) {
						continue;
					}
					rowNum = lastCount;
				}
				Sheet wbSheet = wb.createSheet("page" + (c+1));
				executor.execute(new PageTask(downLatch, wbSheet, rowNum));
			}
			try {
				downLatch.await();
				wb.write(targetFile);
				targetFile.flush();
				targetFile.close();
				long end = System.currentTimeMillis();
				long seconds = (end - start)/1000;
				System.out.println("线程池导出100w条数据花费时间:"+seconds+" s");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			//这里是单页小于一定数直接使用单线程就好
			long start = System.currentTimeMillis();
			SXSSFWorkbook wb = new SXSSFWorkbook();
			Sheet sheet = wb.createSheet("page" + 1);
			Row row =null;

			for (int i = 0; i < total; i++) {
				row = sheet.createRow(i + 1);
				for (int j = 0; j < 10; j++) {
					row.createCell(j).setCellValue("test "+j);
				}
			}

			wb.write(targetFile);
			targetFile.flush();
			targetFile.close();
			long end = System.currentTimeMillis();
			long seconds = (end - start)/1000;
			System.out.println("导出100w条数据花费时间:"+seconds+" s");
		}

	}
public class PageTask implements Runnable {
    public static Logger logger = Logger.getLogger(PageTask.class);
    private CountDownLatch countDownLatch;
    private Sheet sheet;
    private List<TerminalExportDTO> data;
    private String lang;
    private CellStyle style;

    public PageTask(CountDownLatch countDownLatch, Sheet sheet, String lang, CellStyle style, List<TerminalExportDTO> data){
        this.countDownLatch = countDownLatch;
        this.sheet = sheet;
        this.data = data;
        this.lang = lang;
        this.style = style;
    }

    @Override
    public void run() {
        try {
            Row row =null;
            int total = data.size();
            //设置列标题
            Row row2 = sheet.createRow(0);
            String[] rowsName ;
            rowsName = new String[] {};
            for (int i = 0; i < rowsName.length; i++) {
                Cell cell2 = row2.createCell(i);
                cell2.setCellStyle(style);
                cell2.setCellValue(rowsName[i]);
            }

            //设置数据
          	for (int i = 0; i < total; i++) {
				row = sheet.createRow(i + 1);
				for (int j = 0; j < 10; j++) {
					row.createCell(j).setCellValue("test "+j);
				}
			}
           
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("PageTask error", e);
        } finally {
            if (countDownLatch != null) {
                countDownLatch.countDown();
            }
        }
    }

}
	//单元格样式
	private static CellStyle createCellStyle(SXSSFWorkbook workbook, short fontsize) {
		// TODO Auto-generated method stub
		CellStyle style = workbook.createCellStyle();
		style.setAlignment(CellStyle.ALIGN_CENTER);// 水平居中
		style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);// 垂直居中
		// 创建字体
		Font font = workbook.createFont();
		font.setBoldweight(Font.BOLDWEIGHT_BOLD);
		font.setFontHeightInPoints(fontsize);
		// 加载字体
		style.setFont(font);
		return style;
	}

备注

不好意思,看代码的人估计要哭了,有些代码确实对不上,你拷贝以上代码也可能运行不了,上面只是个代码框架,你只要改改数据,传入你要写入的数据,就差不多能用了。因为我再测试完之后,直接原地修改,用于项目了,所以设计相关信息,只能删除了。。。。抱歉。

总之,说下思路,数据大,你就用多线程写入多个sheet。数据小,单线程搞定。
而且excel这个类针对数据大用的,如果小也没啥优势。至于线程池怎么用,基本功,不适合本篇内容。