相关文章推荐
博学的板凳  ·  Java设置POI XSSFCell ...·  1 周前    · 
不羁的饺子  ·  Java POI (3)—— ...·  1 周前    · 
内向的馒头  ·  POI导出excel执行公式 ...·  1 周前    · 
想表白的面包  ·  深海 - 搜狗百科·  7 月前    · 

1. 背景

项目上需要对报表进行打印,前提是用户自己上传excel模板,设置页眉页脚及表格样式,由后端根据参数获取模板后和数据后,将数据写入excel中返回给前端转为pdf预览及打印。已有接口是用poi的SXSSFWorkbook操作excel,具体实现 这篇文章 已经说明。

现在需求变更,需要根据用户在模板中设置的表达式,将数据继承模板中样式输出到excel表格中。这样能让用户自定义设置表格样式,而非系统给定默认样式。

2. 遇到的问题

实现过程中,需要获取模板中已设置的excel,并循环所有行找到表达式填充数据。通过SXSSFWorkbook无法直接将流转换,只能先转换为XSSFWorkbook,再实例化SXSSFWorkbook。具体请看上面提到的文章内容

XSSFWorkbook workbook = new XSSFWorkbook(file1);
// 转换为SXSSFWorkbook
SXSSFWorkbook wbook = new SXSSFWorkbook(workbook);

使用 wbook.getSheetAt(0).getLastRowNum() 却无法获取模板中设置的最后行号。查看源码

    public SXSSFWorkbook(XSSFWorkbook workbook){
    	this(workbook, DEFAULT_WINDOW_SIZE);

而使用workbook.getSheetAt(0).getLastRowNum()却能获取到。

而且有点难受的是,使用wbook.getSheetAt(0).getRow(0)获取到的为null,而使用wbook.getSheetAt(0).createRow(0)想去创建新行覆盖的时候又抛出异常,原因看以下源码

* Create a new row within the sheet and return the high level representation * @param rownum row number * @return high level Row object representing a row in the sheet * @throws IllegalArgumentException If the max. number of rows is exceeded or * a rownum is provided where the row is already flushed to disk. * @see #removeRow(Row) @Override public SXSSFRow createRow(int rownum) int maxrow = SpreadsheetVersion.EXCEL2007.getLastRowIndex(); if (rownum < 0 || rownum > maxrow) { throw new IllegalArgumentException("Invalid row number (" + rownum + ") outside allowable range (0.." + maxrow + ")"); // attempt to overwrite a row that is already flushed to disk if(rownum <= _writer.getLastFlushedRow() ) { throw new IllegalArgumentException( "Attempting to write a row["+rownum+"] " + "in the range [0," + _writer.getLastFlushedRow() + "] that is already written to disk."); // attempt to overwrite a existing row in the input template if(_sh.getPhysicalNumberOfRows() > 0 && rownum <= _sh.getLastRowNum() ) { throw new IllegalArgumentException( "Attempting to write a row["+rownum+"] " + "in the range [0," + _sh.getLastRowNum() + "] that is already written to disk."); SXSSFRow newRow = new SXSSFRow(this); _rows.put(rownum, newRow); allFlushed = false; if(_randomAccessWindowSize >= 0 && _rows.size() > _randomAccessWindowSize) { try { flushRows(_randomAccessWindowSize); } catch (IOException ioe) { throw new RuntimeException(ioe); return newRow;

代码走到第三个if的时候被逮住住抛出异常,真正有数据的是_sh,而不是_rows。但代码又不能获取到_sh

吐槽一下:无法理解写这个工具类的开发是怎么思考问题的,既让我们用,用起来又很难受

3. 解决方案

如果没有版本要求,时间也不够充裕,还是降低版本,使用XSSFWorkbook操作excel吧,懒得去纠结了,更有可能需要降低到HSSFWorkbook。反正操作方式基本相同,只是兼容的excel有些出入而已。

如果一定需要使用SXSSFWorkbook,那就去研究研究代码,看看如何解决这些问题。本人迫于时间紧任务重,只能委曲求全降低版本先实现功能了。

本jar包解决原来系统中已经使用了POI3.7导出excel发生内存溢出的问题 用法:系统中POI3.7的包不需要移除,直接附加上本jar包即可,导出时使用SXSSFWorkbook类,用法与HSSFWorkbook一致 注:本jar包是从POI3.8中整合而得,其中拥有一些与3.7相同类名的类,但路径不同,import类时需要注意选择路径 使用的POI版本为3.10.1,版本较老 项目里遇到需要读取特定模板,然后将数据装载在模板里导出的场景(之前用的都是XSSFWorkbook导出)。但是当你数据量过大时,官方XSSFWorkbook说最多导出65535行,但是个人实际操作后发现远远没到这个数量,两万左右就报OOM(内存溢出)了。 因此,为了解决大数据量导出的问题,查完官方文档之后,可以使用SXSSFWorkbook导出。但... 原因是new SXSSFWorkbook(new XSSFWorkbook(inputStream))的时候,SXSSFWorkbook对象内部会维护一个HashMap(反编译后的名称为_xFromSxHash);当使用workBok.getSheetAt(0)的时候,其实是从_xFromSxHash中获取新创建的Sheet对象;从而导致sheet.getRow(0)获取的row为null。这种方式创建的Workbook,使用sheet.getRow(0)获取的row为null; 最近在做的需求中需要将两个Excel合并。 首先讲下POI中处理Excel的几种方式吧。 1.HSSFWorkbook,用来处理.xls后缀的Excel,即适用于Excel2003以前(包括2003)的版本。因为其最大只能处理65535行的数据,所以现在已经很少使用了,所以本文直接忽略该方式。 2.XSSFWorkbook是现在处理Excel比较常见的方式。其适用于.xlsx后缀的Excel,即E... 我在第一张纸上使用包含2个表的模板文件 . 我需要在第一张纸上执行2次操作 .有Locations数据表列 Headers (例如sr.no,位置和相关数据字段),我需要在其中使用XSSFWorkbook,以便我可以根据位置的大小向下移动行 .有设备表,我需要使用流API,即SXSSFWorkbook对象我使用XSSFWorkbook创建了工作簿对象,向下移动了行,然后尝试将工作簿换为SXSSF... new SXSSFWorkbook(new XSSFWorkbook(inputStream)); 这种方式创建的Workbook,使用sheet.getRow(0)获取的row为null; 原因是new SXSSFWorkbook(new XSSFWorkbook(inputStream))的时候,SXSSFWorkbook对象内部会维护一个HashMap(反编译后的名称为_xFromSxHash); 当使用workBok.getSheetAt(0)的时候,其实是从_xFromSxHash中获取新创建的S 今天在做项目中,遇到使用代码生成具有一定样式的Excel,找了很多资料,最后终于解决了,Excel中格式的设置,以及单元格的合并等等。下面就介绍下,使用NPOI类库操作Excel的方法。   1.首先我们先在内存中生成一个Excel文件,代码如下:     HSSFWorkbook book = new HSSFWorkbook();        ISheet sheet = book.CreateSheet(“Sheet1”);   2.然后在新创建的sheet里面,创建我们的行和列,代码如下: 代码如下:IRow row = sheet.CreateRow(index);//index代 File test = new File("D:\\test.xlsx"); try { XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(test)); SXSSFWorkbook workbook = new SXSSFWorkbook(wb); Sheet sheet = workbook.getSheetAt(0); for (int i = 0; i < 5; i++) { Row row = sheet.getRow(i); if(row==null){ System.out.println(i+":null"); } catch (Exception e) { e.printStackTrace(); 最近在项目中遇到这样的场景,将一批json文件(上千个)数据为list后,按照给定的excel模版格式,填充到模版中生成最终的excel文件。但是因为json文件过多,或者json文件中为list后的数据量过大造成了oom异常:java.lang.OutOfMemoryError:Java heap space。 原因在于XSSFWorkbook创建的 book sheet row cell 等,此时是存在内存的并没有持久化,那么随着数据量增大内存的需求量也就增大,那么很大可能就是要 ... 在一个具有统计功能的系统中,导出excel功能几乎是一定的,如何导出excel?导出的数据有多少?如何高效的导出?Excel简介什么是excel就不用介绍了,这里主要说明不同版本下每个sheet下的行列限制。版本区间行数列数文件后缀Excel 2003及以下65535256xlsExcel 2007及以上104857616384xlsx由上面可知 Excel 2003及以下是无法实现单s...