当前位置:   article > 正文

Hutool-Excel大数据生成-XXOO_excelutil.getbigwriter

excelutil.getbigwriter

一、准备

对于大量数据输出,采用ExcelWriter容易引起内存溢出,因此有了BigExcelWriter。

* ExcelUtil Excel工具类,读取的快捷方法都被封装于此

* ExcelReader Excel读取器,Excel读取的封装,可以直接构造后使用。

* ExcelWriter Excel生成并写出器,Excel写出的封装(写出到流或者文件),可以直接构造后使用。

 

  1. <!--hutool common 工具包-->
  2. <dependency>
  3. <groupId>cn.hutool</groupId>
  4. <artifactId>hutool-all</artifactId>
  5. <version>5.0.7</version>
  6. </dependency>
  7. <!--说明 hutool-4.x的poi-ooxml 版本需高于 3.17(别问我3.8版本为啥不行,因为3.17 > 3.8
  8. hutool-5.x的poi-ooxml 版本需高于 4.1.2 xercesImpl版本高于2.12.0-->
  9. <!--poi-ooxml-->
  10. <dependency>
  11. <groupId>org.apache.poi</groupId>
  12. <artifactId>poi-ooxml</artifactId>
  13. <version>4.1.2</version>
  14. </dependency>
  15. <!--xercesImpl-->
  16. <dependency>
  17. <groupId>xerces</groupId>
  18. <artifactId>xercesImpl</artifactId>
  19. <version>2.12.0</version>
  20. </dependency>

二、代码示例

  1. package com.yl.excel;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.core.io.FileUtil;
  5. import cn.hutool.json.JSON;
  6. import cn.hutool.poi.excel.BigExcelWriter;
  7. import cn.hutool.poi.excel.ExcelReader;
  8. import cn.hutool.poi.excel.ExcelUtil;
  9. import cn.hutool.poi.excel.ExcelWriter;
  10. import cn.hutool.poi.excel.sax.Excel03SaxReader;
  11. import cn.hutool.poi.excel.sax.Excel07SaxReader;
  12. import cn.hutool.poi.excel.sax.handler.RowHandler;
  13. import cn.hutool.poi.word.Word07Writer;
  14. import com.yl.entity.User;
  15. import lombok.extern.slf4j.Slf4j;
  16. import java.awt.*;
  17. import java.time.LocalDateTime;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.concurrent.*;
  23. /**
  24. * 描述: Excel大数据生成-BigExcelWriter
  25. * 对于大量数据输出,采用ExcelWriter容易引起内存溢出,因此有了BigExcelWriter,使用方法与ExcelWriter完全一致
  26. *
  27. * @author: yanglin
  28. * @Date: 2020-07-13-16:19
  29. * @Version: 1.0
  30. */
  31. @Slf4j
  32. public class HutoolExcel {
  33. /**
  34. * ExcelUtil Excel工具类,读取的快捷方法都被封装于此
  35. * ExcelReader Excel读取器,Excel读取的封装,可以直接构造后使用。
  36. * ExcelWriter Excel生成并写出器,Excel写出的封装(写出到流或者文件),可以直接构造后使用。
  37. */
  38. /**
  39. * 创建Excel
  40. * @param excelName
  41. */
  42. public static void testCreateExcel(String excelName){
  43. List<?> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd", DateUtil.date(), 3.22676575765);
  44. List<?> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1", DateUtil.date(), 250.7676);
  45. List<?> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2", DateUtil.date(), 0.111);
  46. List<?> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3", DateUtil.date(), 35);
  47. List<?> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4", DateUtil.date(), 28.00);
  48. List<List<?>> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);
  49. BigExcelWriter writer= ExcelUtil.getBigWriter(excelName);
  50. // 一次性写出内容,使用默认样式
  51. writer.write(rows);
  52. // 关闭writer,释放内存
  53. writer.close();
  54. }
  55. /**
  56. * 创建Word
  57. * @param wordName
  58. */
  59. public static void testCreateWord(String wordName){
  60. Word07Writer writer = new Word07Writer();
  61. // 添加段落(标题)
  62. writer.addText(new Font("方正小标宋简体", Font.PLAIN, 22), "我是第一部分", "我是第二部分");
  63. // 添加段落(正文)
  64. writer.addText(new Font("宋体", Font.PLAIN, 22), "我是正文第一部分", "我是正文第二部分");
  65. // 写出到文件
  66. writer.flush(FileUtil.file(wordName));
  67. // 关闭
  68. writer.close();
  69. }
  70. /**
  71. * Excel读取-ExcelReader
  72. * @param excelName
  73. */
  74. public static void readExcel(String excelName){
  75. // 读取Excel中所有行和列,都用列表表示
  76. ExcelReader reader = ExcelUtil.getReader(excelName);
  77. List<List<Object>> readAll = reader.read();
  78. // 读取为Map列表,默认第一行为标题行,Map中的key为标题,value为标题对应的单元格值。
  79. ExcelReader readerMap = ExcelUtil.getReader(excelName);
  80. List<Map<String,Object>> readMapAll = readerMap.readAll();
  81. // 读取为Bean列表,Bean中的字段名为标题,字段值为标题对应的单元格值。
  82. ExcelReader readerClass = ExcelUtil.getReader("d:/aaa.xlsx");
  83. List<Object> all = readerClass.readAll(Object.class);
  84. }
  85. /**
  86. * 流方式读取Excel2003-Excel03SaxReader
  87. * Excel03SaxReader只支持Excel2003格式的Sax读取。
  88. * 在标准的ExcelReader中,如果数据量较大,读取Excel会非常缓慢,并有可能造成内存溢出。因此针对大数据量的Excel,Hutool封装了event模式的读取方式。
  89. * @param excelName
  90. */
  91. public static void readStream2003Excel(String excelName){
  92. // ExcelUtil快速读取
  93. ExcelUtil.read03BySax(excelName, 1, createRowHandler());
  94. // 构建对象读取
  95. Excel03SaxReader reader = new Excel03SaxReader(createRowHandler());
  96. // reader方法的第二个参数是sheet的序号,-1表示读取所有sheet,0表示第一个sheet,依此类推。
  97. reader.read(excelName, 0);
  98. }
  99. /**
  100. * 首先我们实现一下RowHandler接口,这个接口是Sax读取的核心,通过实现handle方法编写我们要对每行数据的操作方式
  101. * (比如按照行入库,入List或者写出到文件等)
  102. * @return
  103. */
  104. private static RowHandler createRowHandler() {
  105. return new RowHandler() {
  106. @Override
  107. public void handle(int sheetIndex, int rowIndex, List<Object> rowlist) {
  108. log.info("[{}] [{}] {}", sheetIndex, rowIndex, rowlist);
  109. }
  110. };
  111. }
  112. /**
  113. * 流方式读取Excel2007-Excel07SaxReader
  114. * 在标准的ExcelReader中,如果数据量较大,读取Excel会非常缓慢,并有可能造成内存溢出。因此针对大数据量的Excel,Hutool封装了Sax模式的读取方式。
  115. * Excel07SaxReader只支持Excel2007格式的Sax读取。
  116. * @param excelName
  117. */
  118. public static void readStream2007Exce(String excelName){
  119. // ExcelUtil快速读取
  120. ExcelUtil.read07BySax(excelName, 0, createRowHandler());
  121. // 构建对象读取
  122. Excel07SaxReader reader = new Excel07SaxReader(createRowHandler());
  123. reader.read(excelName, 0);
  124. }
  125. /**
  126. * Excel生成-ExcelWriter
  127. * Hutool将Excel写出封装为ExcelWriter,原理为包装了Workbook对象,每次调用merge(合并单元格)或者
  128. * write(写出数据)方法后只是将数据写入到Workbook,并不写出文件,只有调用flush或者close方法后才会真正写出文件。
  129. * 由于机制原因,在写出结束后需要关闭ExcelWriter对象,调用close方法即可关闭,此时才会释放Workbook对象资源,
  130. * 否则带有数据的Workbook一直会常驻内存。
  131. *
  132. * @param toExcelName
  133. */
  134. public static void createExcel(String toExcelName){
  135. // 1. 将行列对象写出到Excel
  136. List<String> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd");
  137. List<String> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1");
  138. List<String> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2");
  139. List<String> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3");
  140. List<String> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4");
  141. List<List<String>> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);
  142. //通过工具类创建writer
  143. ExcelWriter writer = ExcelUtil.getWriter(toExcelName);
  144. //通过构造方法创建writer
  145. //ExcelWriter writer = new ExcelWriter("d:/writeTest.xls");
  146. //跳过当前行,既第一行,非必须,在此演示用
  147. writer.passCurrentRow();
  148. //合并单元格后的标题行,使用默认标题样式
  149. writer.merge(row1.size() - 1, "测试标题");
  150. //一次性写出内容,强制输出标题
  151. writer.write(rows, true);
  152. //关闭writer,释放内存
  153. writer.close();
  154. }
  155. /**
  156. * 测试excel导出百万条记录
  157. * @param data
  158. * @param toExcelName
  159. */
  160. public static void createExcelData(List<List<?>> data, String toExcelName){
  161. //通过工具类创建writer
  162. BigExcelWriter writer= ExcelUtil.getBigWriter(toExcelName);
  163. // 一次性写出内容,使用默认样式
  164. writer.write(data);
  165. // 关闭writer,释放内存
  166. writer.close();
  167. }
  168. public static List<List<?>> createMillionExcelData(){
  169. // 测试excel导出百万条记录 创建测试数据
  170. User user;
  171. List<List<?>> users = new ArrayList<>();
  172. for (int i = 0; i < 10000; i++) {
  173. user = User.builder().id(i).name("东芝王哥"+i).sex("Y").age(10+i)
  174. .love("吃饭睡觉大殴打"+i).eat("吃大虾"+i).run("徒步5000"+i+"米")
  175. .idCard("42595956874412454554"+i).birthday(LocalDateTime.now())
  176. .securityCode("1245"+i).account("adminqwe"+i).password("qwer"+i)
  177. .remark("z这是一个爱好学习、天天向上的bgm"+i)
  178. .build();
  179. // log.info("第 {} 个user::{}", i, user.toString());
  180. String[] userStr = user.toString().substring(
  181. user.toString().indexOf("(") + 1, user.toString().lastIndexOf(")")).split(",");
  182. List<String> userStrs = CollUtil.newArrayList(userStr);
  183. List<String> userStrNews = new ArrayList<>();
  184. if (i == 0) {
  185. userStrs.forEach( u -> {
  186. u = u.split("=")[0];
  187. userStrNews.add(u);
  188. });
  189. }else{
  190. userStrs.forEach( u -> {
  191. u = u.split("=")[1];
  192. userStrNews.add(u);
  193. });
  194. }
  195. users.add(userStrNews);
  196. }
  197. return users;
  198. }
  199. /**
  200. * 并发创建测试数据
  201. *
  202. * @param toExcelName
  203. * @throws ExecutionException
  204. * @throws InterruptedException
  205. */
  206. public static void createMillionExcelDataFuture(String toExcelName) throws ExecutionException, InterruptedException {
  207. long start = System.currentTimeMillis();
  208. log.info("createMillionExcelDataFuture start {} ", start);
  209. // 定时多个FutureTask生成数据
  210. FutureTask<List<List<?>>> taskOne = new FutureTask(new Callable() {
  211. @Override
  212. public Object call() throws Exception {
  213. return createMillionExcelData();
  214. }
  215. });
  216. FutureTask<List<List<?>>> taskTwo = new FutureTask(new Callable() {
  217. @Override
  218. public Object call() throws Exception {
  219. return createMillionExcelData();
  220. }
  221. });
  222. Thread thread1 = new Thread(taskOne);
  223. thread1.start();
  224. Thread thread2 = new Thread(taskTwo);
  225. thread2.start();
  226. List<List<?>> data = new ArrayList<>();
  227. // 得到FutureTask生成的结果 阻塞
  228. List<List<?>> oneList = taskOne.get();
  229. data.addAll(oneList);
  230. List<List<?>> twoList = taskTwo.get();
  231. data.addAll(twoList);
  232. // 设置表头
  233. // 生成excel
  234. //通过工具类创建writer
  235. BigExcelWriter writer= ExcelUtil.getBigWriter(toExcelName);
  236. // 一次性写出内容,使用默认样式
  237. writer.write(data);
  238. // 关闭writer,释放内存
  239. writer.close();
  240. log.info("createMillionExcelDataFuture end 耗时 {}", System.currentTimeMillis() - start);
  241. }
  242. public static void main(String[] args) {
  243. String proDir = System.getProperty("user.dir") +"/springboot-jacob/src/main/resources";
  244. String excelName = proDir + "/excel/"+System.currentTimeMillis()+"test.xlsx";
  245. /*String wordName = proDir + "/word/"+System.currentTimeMillis()+"test.doc";
  246. log.info("创建一个excel.................");
  247. testCreateExcel(excelName);
  248. log.info("创建一个word.................");
  249. testCreateWord(excelName);*/
  250. try {
  251. createMillionExcelDataFuture(excelName);
  252. } catch (ExecutionException e) {
  253. e.printStackTrace();
  254. } catch (InterruptedException e) {
  255. e.printStackTrace();
  256. }
  257. }
  258. }

参考Hutool文档 https://www.hutool.cn/docs/#/poi/Excel%E5%A4%A7%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90-BigExcelWriter

以上 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/43555
推荐阅读
相关标签
  

闽ICP备14008679号