首页 > 编程语言 >Java 利用POI对象 SXSSFWorkbook 导出Excel

Java 利用POI对象 SXSSFWorkbook 导出Excel

时间:2023-06-13 11:46:58浏览次数:54  
标签:Java Excel SXSSFWorkbook user new userDto final 内存

最开始调用的方法是(标记的地方):  workbook = new HSSFWorkbook();和 workbook = new XSSFWorkbook();

这两个方法就是导出Excel的最关键的方法,接下来我来说说这两个方法作用:

1.HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls;

2.XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx;

对于不同版本的EXCEL文档要使用不同的工具类,如果使用错了,会提示如下错误信息。

org.apache.poi.openxml4j.exceptions.InvalidOperationException

org.apache.poi.poifs.filesystem.OfficeXmlFileException

当数据量超出65536条后,在使用HSSFWorkbook或XSSFWorkbook,程序会报OutOfMemoryError:Javaheap space;内存溢出错误。

而我们的数据量达到了9W条数据,用这两个方法肯定是报内存溢出的错误的。

最终我找到的解决方法是:从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的API----SXSSFWorkbook。

3.SXSSFWorkbook-来至官方的解释:实现“BigGridDemo”策略的流式XSSFWorkbook版本。这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行部分被保存在内存中。您可以提供用作书面数据基础的模板工作簿。有关详细信息,请参见https://poi.apache.org/spreadsheet/how-to.html#sxssf。请注意,仍然可能会消耗大量内存,这些内存基于您正在使用的功能,例如合并区域,注释......仍然只存储在内存中,因此如果广泛使用,可能需要大量内存。SXSSFWorkbook默认使用内联字符串而不是共享字符串表。这非常有效,因为没有文档内容需要保存在内存中,但也被称为制作与某些客户不兼容的文档。在启用共享字符串的情况下,文档中的所有唯一字符串必须保存在内存中。根据您的文档内容,这可能比共享字符串被禁用时使用更多的资源。在决定是否启用共享字符串之前,请仔细检查您的内存预算和兼容性需求。

而在poi架包中提供的方法用的是:

当数据量超过1000条时就会调用SXSSFWorkbook方法,从而解决了海量的数据导出会发生内存溢出的问题。

public void exportContacts(final PortalUserPage page, final HttpServletRequest request,  
           final HttpServletResponse response) throws Exception {  
  
       final String name = "通讯录列表";  
  
       // 去掉分页  
       page.setPage(1);  
       page.setRows(Integer.MAX_VALUE);  
       final List<CmssPortalUser> dataList = (List<CmssPortalUser>) this.queryPortalUserListWithGroup(page);  
       final List<PortalUserExcelDto> userList = new ArrayList<>();  
       for (final CmssPortalUser user : dataList) {  
           final PortalUserExcelDto userDto = new PortalUserExcelDto();  
           userDto.setIndex(user.getIndex() != null ? user.getIndex().toString() : "0");  
           userDto.setRealName(user.getRealName());  
           userDto.setCompany(user.getCompany());  
           userDto.setCompanyBranch(user.getCompanyBranch());  
           userDto.setDepartment(user.getDepartment());  
           userDto.setTitle(user.getTitle());  
           userDto.setPhone(user.getPhone());  
           userDto.setLoginName(user.getLoginName());  
           userDto.setProducts(user.getProducts());  
           userDto.setEmail(user.getEmail());  
           userDto.setGroup(user.getGroup());  
           if (user.getOpenTime() != null) {  
               // 开通时间日期格式化  
               final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
               userDto.setOpenTime(format.format(user.getOpenTime()));  
           }  
           // 判断全局预览  
           // 根据创建者ID查询该用户是否可以浏览全局  
           user.setIfGlobelView(shareJedis.ifGlobelView(user.getId().longValue()) ? 1 : 0);  
           if (user.getIfGlobelView() != null) {  
               if (user.getIfGlobelView() == Constants.CURRENCY.ZERO) {  
                   userDto.setIfGlobelView("否");  
               }  
               if (user.getIfGlobelView() == Constants.CURRENCY.ONE) {  
                   userDto.setIfGlobelView("是");  
               }  
           }  
           // 判断状态  
           if (StringUtils.isNotBlank(user.getStatus())) {  
               if (Constants.CONTACTS_STATUS.UNAVAILABILITY.equals(user.getStatus())) {  
                   userDto.setStatus("停用");  
               }  
               if (Constants.CONTACTS_STATUS.AVAILABILITY.equals(user.getStatus())) {  
                   userDto.setStatus("启用");  
               }  
           }  
           // VIP类别  
           userDto.setVipCategory(user.getVipCategoryName() != null ? user.getVipCategoryName() : null);  
           // Vip级别  
           userDto.setVipLevel(user.getVipLevelName() != null ? user.getVipLevelName() : null);  
           // 判断短信通知  
           if (user.getIsSendSms() != null) {  
               if (Constants.UNIVERSAL_CONSTANT.ZERO.equals(user.getIsSendSms())) {  
                   userDto.setIsSendSms("否");  
               }  
               if (Constants.UNIVERSAL_CONSTANT.ONE.equals(user.getIsSendSms())) {  
                   userDto.setIsSendSms("是");  
               }  
           }  
           userList.add(userDto);  
       }  
  
       final ExportParams params = new ExportParams(name, name, ExcelType.XSSF);  
       final Workbook workbook = ExcelExportUtil.exportExcel(params, PortalUserExcelDto.class, userList);  
  
       try {  
           final String agent = request.getHeader("User-Agent").toLowerCase();  
           // 开始下载文件  
           final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
           String filename = format.format(new Date().getTime()) + "-" + name + ".xlsx";  
           if (!StringUtils.isEmpty(agent) && agent.contains("msie") || agent.contains("like gecko")  
                   || (agent.indexOf("rv") > 0 && agent.indexOf("firefox") == -1)) {  
               filename = URLEncoder.encode(filename, "UTF-8");  
           } else {  
               filename = new String(filename.getBytes("UTF-8"), "ISO882023年06月12日");  
           }  
           response.setContentType("application/octet-stream");  
  
           response.setHeader("Content-Disposition", "attachment;filename=".concat(filename));  
  
           final OutputStream out = response.getOutputStream(); 
       //写内容,xls文件已经可以打开 workbook.write(out); out.flush(); } catch (IOException e) { log.error(e.getMessage()); } finally {
      try {
        out.close();
        //删除之前保存的临时文件
        wb.dispose();
      } catch (Exception ex){
        logger.error("export io exception");
      }
    } }

二、SXSSFWorkbook:低内存占用的工作簿

引用官方的介绍,简单概括就是:
SXSSF是对XSSF的一种流式扩展,特点和原理是采用了滑动窗口的机制,低内存占用,主要用于数据量非常大的电子表格而虚拟机堆有限的情况。

SXSSFWorkbook.DEFAULT_WINDOW_SIZE默认值是100,表示在内存中最多存在100个Row对象,当写第101个Row对象的时候就会把第1个Row对象以XML格式写入C:\Users\wange\AppData\Local\Temp路径下的临时文件中,后面的以此类推,始终保持内存中最多存在100个Row对象。

SXSSFWorkbook默认使用内联字符串而不是共享字符串表(SharedStringsTable)。启用共享字符串时,文档中的所有唯一字符串都必须保存在内存中,因此XSSF会占用更多的内存。

与XSSF的对比,在一个时间点上,只可以访问一定数量的Row;不再支持Sheet.clone();不再支持公式的求值。但是除了滑动窗口,其余的EXCLE操作仍然使用的是XSSF的API。

官方提示导出EXCEL后应该调用wb.dispose()来删除之前保存的临时文件。

三、SXSSFWorkbook导出Excel示例

通过poi导出excel的过程大致是这样的:

  • 导入POI的jar包,使用对应的POI对象(本篇选择SXSSFWorkbook)
  • 创建 sheet 表
  • 创建 row 行
  • 创建 cell 每行的单元格(可设置数据的格式,和单元格的格式)
  • 也可在所有数据写好之后,整体对某列某行来设置格式
  • 通过IO流输出

SXSSFWorkbook的使用,与HSSFWorkbook基本一致,只需要换掉对应的Sheet、Row、Cell等类就可以了;

sheet,row,cell在建立的时候Index都是从0开始的;

四、SXSSF单元的样式设置,标红加粗之类

// 设置单元格各种样式
// 设置字体
Font font = wb.createFont();
//字体高度
font.setFontHeightInPoints((short) 11); 
//字体颜色
font.setColor(Font.COLOR_NORMAL); 
//字体
font.setFontName("宋体"); 

//设置单元格里的字体样式,使用上面设置对字体样式,以及设置单元格的格式
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setFont(font);
//水平布局:居中
cellStyle.setAlignment(CellStyle.ALIGN_CENTER); 
//单元格垂直居中
cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
//换行
cellStyle.setWrapText(true);

五、对于身份证等长数字数据,设置CELL单元格为文本格式

/**
*设置CELL格式为文本格式  
*/
CellStyle cellStyle = wb.createCellStyle();  
DataFormat format = wb.createDataFormat();  

//"@"是指文本的数据格式,主要是这段代码
cellStyle.setDataFormat(format.getFormat("@"));  
cell.setCellStyle(cellStyle);  
cell.setCellValue(你的值);
  
//CELL_TYPE_STRING是单元格格式,这里写不写没区别…… 原因如下解释
cell.setCellType(Cell.CELL_TYPE_STRING);

 

标签:Java,Excel,SXSSFWorkbook,user,new,userDto,final,内存
From: https://www.cnblogs.com/min225016/p/17477077.html

相关文章

  • Java判断一个List中是否有重复元素
    1.将List转为Set,通过2个集合的size大小是否相等来判断有无重复元素publicstaticvoidmain(String[]args){ListstringList=newArrayList<>(Arrays.asList("a","a","b","c"));SetstringSet=newHashSet<>(stringList);......
  • Javascript中的内存(垃圾)回收机制
    JavaScript具有自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行常见的垃圾回收方式:标记清除、引用计数方式。一、标记清除方法1、工作原理:【标记“离开环境”的就回收内存】当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“......
  • springcloud 启动失败 YAMLException java.nio.charset.MalformedInputException Inp
     上面这个是错误信息,但是该微服务在本地启动的时候是可以的,但是本地打成jar包本地执行的时候就失败。需要再Java-jar的中间加一下字符编码java-Dfile.encoding=utf-8-jar  myself.jar   myself.jar是自己的jar包问题解决......
  • 根据复杂excel文档模板导出excel表格
    1,首先导入阿里的jar包<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.0.2</version></dependency> 2,将模板excel文件放在对应目录下,取文件时根据存放路径取①模板内容 ②模板存放位置    3,编写util类......
  • java 获取ftp文件列表以及模糊查询,并对结果进行分页
    /***获取ftp文件列表*".*\\.txt":匹配所有以".txt"结尾的文件名。其中,星号(*)表示任意字符序列,反斜杠(\)用于转义点号(.)字符。*".*"+"任意字符"+".*\\.txt":匹配所有包含"表示匹配任意多个任意字符"和以".txt"结尾的文件名。其中,星号(*)表示任意字......
  • this 之谜揭底:从浅入深理解 JavaScript 中的 this 关键字(二)
    前言系列首发于公众号『前端进阶圈』,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。this之谜揭底:从浅入深理解JavaScript中的this关键字(二)调用位置在理解this的绑定过程之前,首先要理解调用位置:调用位置就是函数在代码中被调用的位置(而不是声明的......
  • Java中锁的使用
    目录Java提供了多种锁机制来实现多线程同步和互斥。synchronized关键字ReentrantLockReentrantReadWriteLockSemaphoreCountDownLatch以上是Java中常用的锁机制,不同的锁机制适用于不同的场景。在使用锁时,需要注意避免死锁、饥饿等问题,保证程序的正确性和效率。Java提供了多种锁机......
  • JAVA非递归生成无限级菜单树的较简代码实现。(非泛用型工具包,仅总结逻辑)
    这是一个根据列表生成一个树状结构的较简单实现。搜了搜看起来好像没多少人总结过这种实现。写上来整理一下自己的思路,请大家用用看看,应该用起来问题不大?反正我没遇到BUG。实现的时间复杂度为O(N),空间复杂度应该还是O(N)吧。不过GPT说O(1)可能是因为java的对象实现hash链表是引用而不是......
  • Java的泛型
    泛型是我们需要的程序设计手段。使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。至少在表面上看来,泛型很像C++中的模板。与Java—样,在C++中,模板也是最先被添加到语言中支持强类型集合的。但是,多年之后人......
  • Java 实战介绍 Cookie 和 Session 的区别
    HTTP是一种不保存状态的协议,即无状态协议,HTTP协议不会保存请求和响应之间的通信状态,协议对于发送过的请求和响应都不会做持久化处理。无状态协议减少了对服务压力,如果一个服务器需要处理百万级用户的请求状态,对服务器的压力无疑的是巨大的。无状态的HTTP由于其简单和易用性......