一、准备

对于大量数据输出,采用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() {@Overridepublic 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. 将行列对象写出到ExcelList<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);//通过工具类创建writerExcelWriter 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){//通过工具类创建writerBigExcelWriter 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() {@Overridepublic Object call() throws Exception {return createMillionExcelData();}});FutureTask<List<List<?>>> taskTwo = new FutureTask(new Callable() {@Overridepublic 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//通过工具类创建writerBigExcelWriter 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

以上

Hutool-Excel大数据生成-XXOO相关推荐

  1. Java实现excel大数据量导入

    情景分析: 通常我们通过poi读取excel文件时,若在用户模式下,由于数据量较大.Sheet较多,很容易出现内存溢出的情况 用户模式读取excel的典型代码如下: FileInputStream f ...

  2. 【Apache POI】Excel操作(四):Excel大数据量的写入

    迷茫代表着你身边还有选择,焦虑意味着你手上还有时间. 有目录,不迷路 前言 超量数据 速率比较 原因剖析 超级版本大救星 往期回顾 前言 之前在下面这期Excel操作: [Apache POI]Exc ...

  3. Apache POI和EasyExcel 第三集:Apache POI的Excel大数据量写入(分为03版的xls、07版的xlsx、升级版SXSSF)

    Apache POI和EasyExcel 第三集:Apache POI的Excel大数据量写入(分为03版的xls.07版的xlsx.升级版SXSSF) 一.结果 我的03跑了1.204秒,07跑了5 ...

  4. linux qt写入excel文件内容,Qt 读取Excel表格数据 生成Excel表格并写入数据

    Qt 读取Excel表格数据 生成Excel表格并写入数据 Qt 读取Excel表格数据 生成Excel表格并写入数据 修改.pro文件,增加 axcontainer QT += axcontaine ...

  5. 读取excel大数据量详解

    需求:导入大数据量excel文件到数据库(测试11MB,40w行数据) 首先说结论:都是大概时间,且其中有两个参数需要调,这里统一下参数大小. 监听器中的缓存list一次性存100000(测试过100 ...

  6. python处理excel大数据-Python实现大数据收集至excel的思路详解

    一.在工程目录中新建一个excel文件 二.使用python脚本程序将目标excel文件中的列头写入,本文省略该部分的code展示,可自行网上查询 三.以下code内容为:实现从接口获取到的数据值写入 ...

  7. excel大数据重采样批量操作(每两列中插入新一列,新一列为左右两列的平均值)

    重采样 原理:线性插值 如上图所示,我们每10秒进行一次采样,共得到6个采样值,现在我们像每5秒进行一次采样,在不重新做实验的情况下,对原有数据进行重采样,采用线性插值的方式,也就是每两列中插入一列, ...

  8. python tkinter编写界面,使用win32com操作excel获取数据生成截图后,wxpy登录微信,给租客发送房租(二)

    '''Open_Excel是根据每个excel里的每个租客租金详情,生成房租信息send_info 以及对应的表格图片过程:Open_Excel(月份) 输入月份实例化get_send_info() ...

  9. Excel大数据量单元格快速填充

    个人简介:一个从会计转行数据分析师的三旬老汉 擅长领域:数据分析.数据仓库.大数据 博客内容:平时会将自己工作中遇到的问题进行归纳总结,分享给各位小伙伴,意在帮助大家少加班.不掉发,让我们相互学习,一 ...

最新文章

  1. java理解程序逻辑_使用java理解程序逻辑(12)
  2. 滴滴哆啦A梦源码解析
  3. c语言常量的正确表示const,C语言中的const和free用法详解
  4. python string length_如何使用python获取字符串长度?哪些方法?
  5. 学习OpenStack之 (4): Linux 磁盘、分区、挂载、逻辑卷管理 (Logical Volume Manager)
  6. 训练日志 2018.11.7
  7. clojure 使用Lazy-seq创建斐波那契数列
  8. ArcGIS Pro 有多强大?(一)
  9. Java多线程实现-Runnable接口
  10. win7开机有画面进系统黑屏怎么办
  11. 华硕电脑的触摸板关闭
  12. 简易开发的百度地图API
  13. PIXI+GSAP 防刹车动效
  14. splash : mouse_click()方法
  15. 我的偶像Micheal.Jackson (MTV全集):本来是有一套Micheal的经典VCD的,但被朋友拿走再没还回来……...
  16. 红米4手机(其它小米应该一样)adb 调试(usb ,tcp)
  17. 【合天网安】CONN.ASP暴库漏洞实验
  18. 2021秋季《离散数学》_平面图
  19. 《缠中说禅108课》19:学习缠中说禅技术分析理论的关键
  20. ANSYS学习1--概述

热门文章

  1. adb查看手机cpu的核数
  2. 艾兰岛编辑器-粒子效果
  3. Qt小程序之自绘震动铃铛提示控件
  4. 面试题:为什么ConcurrentHashMap的读操作不需要加锁?
  5. FPGA和CPLD对比
  6. OriginLab.OriginPro.v8.6.SR3.Cracked-EAT
  7. STM32学习之DS18B20数字温度传感器
  8. 聊聊广域网ppp协议和认证
  9. 0x01A686F0 处有未经处理的异常(在 五金上色软件.exe 中): 0xC000041D: 用户回调期间遇到未经处理的异常。。...
  10. Source Insight中无法正确判断宏定义的问题