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...