赞
踩
对于大量数据输出,采用ExcelWriter容易引起内存溢出,因此有了BigExcelWriter。
* ExcelUtil Excel工具类,读取的快捷方法都被封装于此
* ExcelReader Excel读取器,Excel读取的封装,可以直接构造后使用。
* ExcelWriter Excel生成并写出器,Excel写出的封装(写出到流或者文件),可以直接构造后使用。
- <!--hutool common 工具包-->
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.0.7</version>
- </dependency>
-
- <!--说明 hutool-4.x的poi-ooxml 版本需高于 3.17(别问我3.8版本为啥不行,因为3.17 > 3.8 )
- hutool-5.x的poi-ooxml 版本需高于 4.1.2 xercesImpl版本高于2.12.0-->
- <!--poi-ooxml-->
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml</artifactId>
- <version>4.1.2</version>
- </dependency>
- <!--xercesImpl-->
- <dependency>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- <version>2.12.0</version>
- </dependency>

- package com.yl.excel;
-
- import cn.hutool.core.collection.CollUtil;
- import cn.hutool.core.date.DateUtil;
- import cn.hutool.core.io.FileUtil;
- import cn.hutool.json.JSON;
- import cn.hutool.poi.excel.BigExcelWriter;
- import cn.hutool.poi.excel.ExcelReader;
- import cn.hutool.poi.excel.ExcelUtil;
- import cn.hutool.poi.excel.ExcelWriter;
- import cn.hutool.poi.excel.sax.Excel03SaxReader;
- import cn.hutool.poi.excel.sax.Excel07SaxReader;
- import cn.hutool.poi.excel.sax.handler.RowHandler;
- import cn.hutool.poi.word.Word07Writer;
- import com.yl.entity.User;
- import lombok.extern.slf4j.Slf4j;
-
- import java.awt.*;
- import java.time.LocalDateTime;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.*;
-
- /**
- * 描述: Excel大数据生成-BigExcelWriter
- * 对于大量数据输出,采用ExcelWriter容易引起内存溢出,因此有了BigExcelWriter,使用方法与ExcelWriter完全一致
- *
- * @author: yanglin
- * @Date: 2020-07-13-16:19
- * @Version: 1.0
- */
- @Slf4j
- public class HutoolExcel {
-
- /**
- * ExcelUtil Excel工具类,读取的快捷方法都被封装于此
- * ExcelReader Excel读取器,Excel读取的封装,可以直接构造后使用。
- * ExcelWriter Excel生成并写出器,Excel写出的封装(写出到流或者文件),可以直接构造后使用。
- */
-
- /**
- * 创建Excel
- * @param excelName
- */
- public static void testCreateExcel(String excelName){
- List<?> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd", DateUtil.date(), 3.22676575765);
- List<?> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1", DateUtil.date(), 250.7676);
- List<?> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2", DateUtil.date(), 0.111);
- List<?> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3", DateUtil.date(), 35);
- List<?> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4", DateUtil.date(), 28.00);
-
- List<List<?>> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);
- BigExcelWriter writer= ExcelUtil.getBigWriter(excelName);
- // 一次性写出内容,使用默认样式
- writer.write(rows);
- // 关闭writer,释放内存
- writer.close();
- }
-
- /**
- * 创建Word
- * @param wordName
- */
- public static void testCreateWord(String wordName){
- Word07Writer writer = new Word07Writer();
- // 添加段落(标题)
- writer.addText(new Font("方正小标宋简体", Font.PLAIN, 22), "我是第一部分", "我是第二部分");
- // 添加段落(正文)
- writer.addText(new Font("宋体", Font.PLAIN, 22), "我是正文第一部分", "我是正文第二部分");
- // 写出到文件
- writer.flush(FileUtil.file(wordName));
- // 关闭
- writer.close();
- }
-
- /**
- * Excel读取-ExcelReader
- * @param excelName
- */
- public static void readExcel(String excelName){
- // 读取Excel中所有行和列,都用列表表示
- ExcelReader reader = ExcelUtil.getReader(excelName);
- List<List<Object>> readAll = reader.read();
-
- // 读取为Map列表,默认第一行为标题行,Map中的key为标题,value为标题对应的单元格值。
- ExcelReader readerMap = ExcelUtil.getReader(excelName);
- List<Map<String,Object>> readMapAll = readerMap.readAll();
-
- // 读取为Bean列表,Bean中的字段名为标题,字段值为标题对应的单元格值。
- ExcelReader readerClass = ExcelUtil.getReader("d:/aaa.xlsx");
- List<Object> all = readerClass.readAll(Object.class);
- }
-
- /**
- * 流方式读取Excel2003-Excel03SaxReader
- * Excel03SaxReader只支持Excel2003格式的Sax读取。
- * 在标准的ExcelReader中,如果数据量较大,读取Excel会非常缓慢,并有可能造成内存溢出。因此针对大数据量的Excel,Hutool封装了event模式的读取方式。
- * @param excelName
- */
- public static void readStream2003Excel(String excelName){
- // ExcelUtil快速读取
- ExcelUtil.read03BySax(excelName, 1, createRowHandler());
-
- // 构建对象读取
- Excel03SaxReader reader = new Excel03SaxReader(createRowHandler());
- // reader方法的第二个参数是sheet的序号,-1表示读取所有sheet,0表示第一个sheet,依此类推。
- reader.read(excelName, 0);
- }
-
- /**
- * 首先我们实现一下RowHandler接口,这个接口是Sax读取的核心,通过实现handle方法编写我们要对每行数据的操作方式
- * (比如按照行入库,入List或者写出到文件等)
- * @return
- */
- private static RowHandler createRowHandler() {
- return new RowHandler() {
- @Override
- public void handle(int sheetIndex, int rowIndex, List<Object> rowlist) {
- log.info("[{}] [{}] {}", sheetIndex, rowIndex, rowlist);
- }
- };
- }
-
- /**
- * 流方式读取Excel2007-Excel07SaxReader
- * 在标准的ExcelReader中,如果数据量较大,读取Excel会非常缓慢,并有可能造成内存溢出。因此针对大数据量的Excel,Hutool封装了Sax模式的读取方式。
- * Excel07SaxReader只支持Excel2007格式的Sax读取。
- * @param excelName
- */
- public static void readStream2007Exce(String excelName){
- // ExcelUtil快速读取
- ExcelUtil.read07BySax(excelName, 0, createRowHandler());
-
- // 构建对象读取
- Excel07SaxReader reader = new Excel07SaxReader(createRowHandler());
- reader.read(excelName, 0);
- }
-
- /**
- * Excel生成-ExcelWriter
- * Hutool将Excel写出封装为ExcelWriter,原理为包装了Workbook对象,每次调用merge(合并单元格)或者
- * write(写出数据)方法后只是将数据写入到Workbook,并不写出文件,只有调用flush或者close方法后才会真正写出文件。
- * 由于机制原因,在写出结束后需要关闭ExcelWriter对象,调用close方法即可关闭,此时才会释放Workbook对象资源,
- * 否则带有数据的Workbook一直会常驻内存。
- *
- * @param toExcelName
- */
- public static void createExcel(String toExcelName){
- // 1. 将行列对象写出到Excel
- List<String> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd");
- List<String> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1");
- List<String> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2");
- List<String> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3");
- List<String> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4");
-
- List<List<String>> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);
-
- //通过工具类创建writer
- ExcelWriter writer = ExcelUtil.getWriter(toExcelName);
- //通过构造方法创建writer
- //ExcelWriter writer = new ExcelWriter("d:/writeTest.xls");
-
- //跳过当前行,既第一行,非必须,在此演示用
- writer.passCurrentRow();
-
- //合并单元格后的标题行,使用默认标题样式
- writer.merge(row1.size() - 1, "测试标题");
- //一次性写出内容,强制输出标题
- writer.write(rows, true);
- //关闭writer,释放内存
- writer.close();
- }
-
- /**
- * 测试excel导出百万条记录
- * @param data
- * @param toExcelName
- */
- public static void createExcelData(List<List<?>> data, String toExcelName){
- //通过工具类创建writer
- BigExcelWriter writer= ExcelUtil.getBigWriter(toExcelName);
- // 一次性写出内容,使用默认样式
- writer.write(data);
- // 关闭writer,释放内存
- writer.close();
- }
-
- public static List<List<?>> createMillionExcelData(){
- // 测试excel导出百万条记录 创建测试数据
- User user;
- List<List<?>> users = new ArrayList<>();
- for (int i = 0; i < 10000; i++) {
- user = User.builder().id(i).name("东芝王哥"+i).sex("Y").age(10+i)
- .love("吃饭睡觉大殴打"+i).eat("吃大虾"+i).run("徒步5000"+i+"米")
- .idCard("42595956874412454554"+i).birthday(LocalDateTime.now())
- .securityCode("1245"+i).account("adminqwe"+i).password("qwer"+i)
- .remark("z这是一个爱好学习、天天向上的bgm"+i)
- .build();
- // log.info("第 {} 个user::{}", i, user.toString());
- String[] userStr = user.toString().substring(
- user.toString().indexOf("(") + 1, user.toString().lastIndexOf(")")).split(",");
- List<String> userStrs = CollUtil.newArrayList(userStr);
- List<String> userStrNews = new ArrayList<>();
-
- if (i == 0) {
- userStrs.forEach( u -> {
- u = u.split("=")[0];
- userStrNews.add(u);
- });
- }else{
- userStrs.forEach( u -> {
- u = u.split("=")[1];
- userStrNews.add(u);
- });
- }
- users.add(userStrNews);
- }
- return users;
- }
-
- /**
- * 并发创建测试数据
- *
- * @param toExcelName
- * @throws ExecutionException
- * @throws InterruptedException
- */
- public static void createMillionExcelDataFuture(String toExcelName) throws ExecutionException, InterruptedException {
- long start = System.currentTimeMillis();
- log.info("createMillionExcelDataFuture start {} ", start);
- // 定时多个FutureTask生成数据
- FutureTask<List<List<?>>> taskOne = new FutureTask(new Callable() {
- @Override
- public Object call() throws Exception {
- return createMillionExcelData();
- }
- });
-
- FutureTask<List<List<?>>> taskTwo = new FutureTask(new Callable() {
- @Override
- public Object call() throws Exception {
- return createMillionExcelData();
- }
- });
-
- Thread thread1 = new Thread(taskOne);
- thread1.start();
- Thread thread2 = new Thread(taskTwo);
- thread2.start();
-
- List<List<?>> data = new ArrayList<>();
-
- // 得到FutureTask生成的结果 阻塞
- List<List<?>> oneList = taskOne.get();
- data.addAll(oneList);
- List<List<?>> twoList = taskTwo.get();
- data.addAll(twoList);
-
- // 设置表头
-
- // 生成excel
- //通过工具类创建writer
- BigExcelWriter writer= ExcelUtil.getBigWriter(toExcelName);
- // 一次性写出内容,使用默认样式
- writer.write(data);
- // 关闭writer,释放内存
- writer.close();
-
- log.info("createMillionExcelDataFuture end 耗时 {}", System.currentTimeMillis() - start);
- }
-
- public static void main(String[] args) {
- String proDir = System.getProperty("user.dir") +"/springboot-jacob/src/main/resources";
- String excelName = proDir + "/excel/"+System.currentTimeMillis()+"test.xlsx";
- /*String wordName = proDir + "/word/"+System.currentTimeMillis()+"test.doc";
- log.info("创建一个excel.................");
- testCreateExcel(excelName);
- log.info("创建一个word.................");
- testCreateWord(excelName);*/
-
- try {
- createMillionExcelDataFuture(excelName);
- } catch (ExecutionException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }

参考Hutool文档 https://www.hutool.cn/docs/#/poi/Excel%E5%A4%A7%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90-BigExcelWriter
以上
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。