POI读取Excel模板并导出大量数据

我在使用XSSFWorkbook读取Excel模板并导出大量数据(百万级)时,发现很长时间没有响应,debugger模式发现在读取第三四十万条数据时,程序直接停了,如下代码:

使用之前首先引入maven依赖,我使用的是POI版本为3.17

 <!-- apache-poi引入 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version></dependency>

问题代码:

 /*** SSOSystemPrivTask.java* 用户对应的角色与权限*/public void exportUserRolePermits() {FileOutputStream out = null;XSSFWorkbook workbook = null;try {//excel模板路径String filePath = "/template/业务系统角色与权限关联数据(模板一).xlsx";//导出路径String exportFilePath = CmUtil.getProps("/conf.properties").getProperty("all_permit_export_path","/"); //读取excel模板InputStream in = SSOSystemPrivTask.class.getResourceAsStream(filePath);workbook = new XSSFWorkbook(in);//获取角色关联权限List<List<String>> privList = this.ssoTaskService.getRolePermits();if (privList != null && privList.size() > 0) {XSSFSheet sheet0 = workbook.getSheetAt(0);//角色对应权限页签//在相应的单元格进行赋值for (int i = 0; i < privList.size(); i++) {Row row = sheet0.getRow(i+1);if (row == null) {row = sheet0.createRow(i+1);}for (int j = 0; j < privList.get(i).size(); j++) {Cell cell = row.getCell(j);if (cell == null) {cell = row.createCell(j); }cell.setCellValue(privList.get(i).get(j));}}}//获取用户关联角色List<List<String>> userRoles = this.ssoTaskService.getUserRoles();if (userRoles != null && userRoles.size() > 0) {XSSFSheet sheet1 = workbook.getSheetAt(1);//用户对应角色页签//在相应的单元格进行赋值for (int i = 0; i < userRoles.size(); i++) {Row row = sheet1.getRow(i+1);if (row == null) {row = sheet1.createRow(i+1);}for (int j = 0; j < userRoles.get(i).size(); j++) {Cell cell = row.getCell(j);if (cell == null) {cell = row.createCell(j); }cell.setCellValue(userRoles.get(i).get(j));}}}//保存文件String fileName = "业务系统角色与权限关联数据(jzyx).xlsx";out = new FileOutputStream(exportFilePath + fileName);workbook.write(out);} catch (Exception e) {logger.error(e.getMessage(), e);} finally {try {if (out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}try {if (workbook != null) {workbook.close();}} catch (IOException e) {e.printStackTrace();}}}

于是我百度了一下,得到如下信息:

HSSFWorkbook和XSSFWorkbook的Excel Sheet导出条数上限(<=2003版)是65535行、256列,(>=2007版)是1048576行,16384列,如果数据量超过了此上限,那么可以使用SXSSFWorkbook来导出。实际上上万条数据,甚至上千条数据就可以考虑使用SXSSFWorkbook了。

但是SXSSFWorkbook不能读取文件。也就是说我们无法读取模板的内容,因此需要将XSSFWorkbook与SXSSFWorkbook结合起来使用。

官方文档里提供了 public SXSSFWorkbook(XSSFWorkbook workbook)构造方法,将XSSFWorkbook转为SXSSFWorkbook。代码如下:

 /*** SSOSystemPrivTask.java* 用户对应的角色与权限*/public void exportUserRolePermits() {FileOutputStream out = null;SXSSFWorkbook workbook = null;try {//excel模板路径String filePath = "/template/业务系统角色与权限关联数据(模板一).xlsx";//导出路径String exportFilePath = CmUtil.getProps("/conf.properties").getProperty("all_permit_export_path","/"); //读取excel模板InputStream in = SSOSystemPrivTask.class.getResourceAsStream(filePath);XSSFWorkbook wb = new XSSFWorkbook(in);workbook = new SXSSFWorkbook(wb, 100);//获取角色关联权限List<List<String>> privList = this.ssoTaskService.getRolePermits();if (privList != null && privList.size() > 0) {SXSSFSheet sheet0 = workbook.getSheetAt(0);//菜单功能权限//在相应的单元格进行赋值for (int i = 0; i < privList.size(); i++) {Row row = sheet0.getRow(i+1);if (row == null) {row = sheet0.createRow(i+1);}for (int j = 0; j < privList.get(i).size(); j++) {Cell cell = row.getCell(j);if (cell == null) {cell = row.createCell(j); }cell.setCellValue(privList.get(i).get(j));}}}//获取用户关联角色List<List<String>> userRoles = this.ssoTaskService.getUserRoles();if (userRoles != null && userRoles.size() > 0) {SXSSFSheet sheet1 = workbook.getSheetAt(1);//用户对应权限//在相应的单元格进行赋值for (int i = 0; i < userRoles.size(); i++) {Row row = sheet1.getRow(i+1);if (row == null) {row = sheet1.createRow(i+1);}for (int j = 0; j < userRoles.get(i).size(); j++) {Cell cell = row.getCell(j);if (cell == null) {cell = row.createCell(j); }cell.setCellValue(userRoles.get(i).get(j));}}}//保存文件String fileName = "业务系统角色与权限关联数据(jzyx).xlsx";out = new FileOutputStream(exportFilePath + fileName);workbook.write(out);} catch (Exception e) {logger.error(e.getMessage(), e);} finally {try {if (out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}try {if (workbook != null) {workbook.close();}} catch (IOException e) {e.printStackTrace();}}}

这里可以通过SXSSFWorkbook.getSheetAt(int index)获得sheet,但是再通过sheet.getRow(int rownum)去获得行时,会发现行数据为空,报空指针异常。
于是我在判断为null时,重新创建了行和列。代码如下:

for (int i = 0; i < privList.size(); i++) {Row row = sheet0.getRow(i+1);if (row == null) {row = sheet0.createRow(i+1);}for (int j = 0; j < privList.get(i).size(); j++) {Cell cell = row.getCell(j);if (cell == null) {cell = row.createCell(j); }cell.setCellValue(privList.get(i).get(j));}
}

经过查询之后,发现原因是因为这些记录存在于XSSFWorkbook中,其实你可以用sxssfWorkbook.getXSSFWorkbook()方法去获取初始模板的行数据。代码如下:

 InputStream in = SSOSystemPrivTask.class.getResourceAsStream(filePath);XSSFWorkbook wb = new XSSFWorkbook(in);SXSSFWorkbook swb = new SXSSFWorkbook(wb,100);XSSFWorkbook xssfWorkbook = swb.getXSSFWorkbook();XSSFSheet sheet = xssfWorkbook.getSheetAt(0);

改用SXSSFWorkbook之后运行报了以下错误:java.lang.IllegalArgumentException: Attempting to write a row[0] in the range [0,3] that is already written to disk.
然后我又百度一番,搜到如下内容:

使用org.apache.poi.xssf.streaming.SXSSFWorkbook进行大数据量导出到excel时,因为SXSSFWorkbook有数据量超过一定范围则刷新到硬盘的机制,即new SXSSFWorkbook(int windowSize)中的windowSize参数。
当通过createRow()创建一个新行并且未刷新记录的总数超过指定的窗口大小时,具有最低索引值的行将被刷新,并且不能再通过getRow()等访问。 比如窗口行数为100,内存当前有100行,createRow()创建一个新行,索引值为0的那一行被刷新到本地文件,该行将无法访问,因为它们已写入磁盘。
如果创建新sheet的行数没有超过windowSize的大小,则不会有此问题,但现在内存中不能存过多数据,而一个sheet中的数据也不能太少,所以windowSize的大小肯定会小于一个sheet中的行数值。

然后,他给出的解决方案是:

SXSSFSheet sheet = workbook.createSheet(sheetName);
//对sheet设置一下无限制访问
sheet.setRandomAccessWindowSize(-1);

然后我试了一下,事实证明我的代码报错并不是这个原因,经过多番查询,也没有找到符合我的代码报错的场景。
这个问题搞了我一下午,我突然想到会不会是模板的原因,因为之前在导入Excel文件的时候,曾经遇到过模板中明明没有数据,却读取到有多行数据的情况,这是因为这些行中曾经被添加过数据,之后这些数据虽然被清空了,但是行的记录却被保留了下来。于是我把模板从上到下选中了很多行,直接删除行,然后重新放到项目目录下,重新执行,问题终于解决了。

最后附上我的导出模板截图:

POI读取Excel模板并导出大量数据相关推荐

  1. poi读取excel模板,并填充数据

    一.POI介绍 Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 基本功能: HSSF - 提供读写 ...

  2. 使用POI读取EXCEL模板并填充数据,上传至腾讯云储存桶

    读取EXCEL模板,并填充数据生成文件 前言 一.POI导入 二.具体实现 1.制作我们的模板 2.读取模板来生成新的EXCEL 3.查看生成结果 三,传到腾讯云储存桶里 1.导入COS依赖 2.写个 ...

  3. java通过poi读取excel中的日期类型数据或自定义类型日期

    java通过poi读取excel中的日期类型数据或自定义类型日期 Java 读取Excel表格日期类型数据的时候,读出来的是这样的  12-十月-2019,而Excel中输入的是 2019/10/12 ...

  4. java hutool poi 基于excel模板文件,填充数据的思路

    需求 用户可下载excel模板文件,填充数据后上传,也可以下载已上传所有数据的excel,模板文件和含数据excel,都有列头及列说明:由此想到模板文件和含数据excel共用一份excel模板,下载数 ...

  5. 记录POI读取excel表格文件,空行校验

    如题,前几天在使用poi读取excel表时,有效数据行数只有几百行,但表格行数有几千行,结果调用sheet.getLastNum时空行也算在内了!本来解析读取就慢,现在更是浪费时间.查了一下终于看到一 ...

  6. poi读取excel多层表头模板写入数据并导出

    poi读取excel多层表头模板写入数据并导出 这两天刚好写excel,写了一份自定义表头的,写了一份模板的,这里展示一份读取excel模板写入数据并导出的 //title excel的名称 head ...

  7. java poi 模板填数据库,java使用POI读取excel模版并向固定表格里填写数据详解

    java使用POI读取excel模版并向固定表格里填写数据详解:public class ExportExcelDemo { private HSSFWorkbook workbook = null; ...

  8. luckySheet+POI+EasyExcel实现在线excel模版的导出和数据填充

    luckySheet+POI+EasyExcel实现在线excel模版的导出和数据填充 业务需求 关键字 luckySheet POI EasyExcel 代码实现 前端luckySheet配置的ex ...

  9. springboot使用POI读取excel数据

    MAVEN坐标如下: 便于复制: <!-- excel导出工具 --> <dependency><groupId>org.apache.poi</groupI ...

最新文章

  1. pandas pivot 占比_数据处理进阶pandas入门(十八)
  2. DeepWalk 和 Node2Vec
  3. matlab表白_表白 | 北航男生想找个女朋友,我身高179,希望女生体贴一点
  4. 目标检测之---R-FCN and R-FCN-3000
  5. 2021年第十二届蓝桥杯 - 省赛 - C/C++大学A组 - D.路径
  6. MySQL Administrator
  7. 腾讯AI开放平台的接口调用指南
  8. Android Studio使用心得
  9. 2017蓝桥杯省赛---java---B---1(购物单)
  10. ogm session_带有Hibernate OGM的NoSQL –第三部分:在WildFly上构建REST应用程序
  11. 华为正式宣布全场景AI计算框架MindSpore开源 降低AI开发门槛
  12. 2021高考分数文科成绩查询,2021高考分数线预测 文科理科分数线是多少
  13. leetcode-反转整数
  14. [转载] python中断响应_用Python脚本监测.py脚本的进程状态,并实现中断重启。
  15. 学习 LLVM(11) iplist 和 ilist
  16. Python-文件的管理
  17. journalctl日志工具使用方法
  18. 行业增长乏力,转型失败案例多,平安银行要转型“对公”?
  19. 地图随意搜---情景地图
  20. 面对无秘,假设你是微信的产品经理浅析

热门文章

  1. 蓝桥杯 基础练习 十进制转换为16进制
  2. php安装和开启curl扩展,php开启curl扩展
  3. HTML图片链接边框半透明,请教,下图登录页如何用css实现?半透明的边框怎么做?...
  4. 【干货分享】移动营销宝典--入门篇
  5. a标签中 href=/ 和 hideFocus=true
  6. 【android开发】手势滑动关闭Activity(随手指消失)的辅助类的实现
  7. 爬虫入门经典(十四) | 使用selenium尝试爬取豆瓣图书
  8. win10扩展显示屏时遇到“Input signal out of range”
  9. 关晓彤同款无米寿司,让你感受一下远离碳水也无敌幸福~
  10. html-frame框架