分析自己遇到的Excel导出报NullpointException问题
此文已由作者叶富宏授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
昨天一个商务反馈说报价信息导出失败,查看了一下日志发现是导出记录到Excel的时候报了NullpointException异常。报错的是下面这个方法里面,标红的代码(dataRow为null)。
private void MergedRowRegion(Sheet sheet, int endRowNum, int rowNum){ if(endRowNum > rowNum){
Row dataRow = sheet.getRow(rowNum); for(int i=0; i< 8; i++){ Cell cell = dataRow.getCell(i);
if(cell != null){
sheet.addMergedRegion(new CellRangeAddress(rowNum, endRowNum, i, i));
}
}
}
}
这个方法的作用是把从rowNum行到endRowNum的第1到第七列进行单元格合并。反复检查了好几遍代码和数据,除了发现数据量比较多以外,并没有发现有什么地方会造成dataRow为null的情况,通过调试终于发现了原因,现在就把这个问题记录一下。
简单说一下导出的业务:导出的信息包含商品、供应商和供应商报价。一个商品可以包含多个供应商信息,每个供应商可以有多个报价。Excel的格式如下:
所以当一个商品对应多个供应商和报价的时候,需要对商品和供应商的信息进行合并单元格。往Excel写入数据的步骤是这样的:首先在第rowNum行写入商品信息、再写入供应商信息和报价信息并对供应商信息进单元格合并,然后返回最后所在的行号endRowNum,最后把endRowNum和rowNum传入上面的方法对商品属性进行单元格合并。报异常的那个商品总共有1739条报价,量有点多。
往Excel写入数据的时候,数据会先保存在SXSSFSheet的_rows里面,_rows是一个TreeMap<Integer, SXSSFRow>,Key是行(Row)的索引,从0开始1,2,3...递增,Value是对应的行数据。通过断点发现_rows里面的数据key是从739开始的740,741,742.....一直到1739总共1000条记录。放入1739条数据,里面只有后面的1000条。通过接下去的调试发现,当_rows里面的数据大于等于1000条的时候,如果再往里面插入一条数据,size依旧是1000,但是最前面的那条数据就被挤出去了(先进先出)。
查看了一下SXSSFSheet里面createRow的方法,找到了原因,代码如下:
public SXSSFRow createRow(int rownum) {
......
SXSSFRow newRow = new SXSSFRow(this, initialAllocationSize); this._rows.put(Integer.valueOf(rownum), newRow); this.allFlushed = false; if(this._randomAccessWindowSize >= 0 && this._rows.size() > this._randomAccessWindowSize) { try { this.flushRows(this._randomAccessWindowSize);
} catch (IOException var7) { throw new RuntimeException(var7);
} return newRow;
......
}
参数rownum是行的下标,也是_rows的key,通过代码发现创建了新的一行以后,
会调用 this.flushRows(this._randomAccessWindowSize);方法,
通过方法名就能知道应该是刷新缓存之类的作用,flushRows方法的代码如下:
public void flushRows(int remaining) throws IOException { while(this._rows.size() > remaining) { this.flushOneRow();
} if(remaining == 0) { this.allFlushed = true;
} }flushOneRow方法的代码如下:private void flushOneRow() throws IOException {Integer firstRowNum = (Integer)this._rows.firstKey();//取出最小的key
if(firstRowNum != null) { int rowIndex = firstRowNum.intValue();
SXSSFRow row = (SXSSFRow)this._rows.get(firstRowNum); this._writer.writeRow(rowIndex, row);//
this._rows.remove(firstRowNum); this.lastFlushedRowNumber = rowIndex;
} }
通过代码可以看到,flushOneRow方法里会取出key最小的一条数据,写入文件中,然后从_rows中删除,让_rows一直维持在1000的大小。
这就解释了为什么放入了1739条数据,_rows中只有1000条,并且存在的都是后面的。
所以当调用sheet.getRow(rowNum)去取那些从_rows删掉的数据就会返回null。
从源码中可以看到,默认情况下_rows的size是保持在100的,而非1000.
public static final int DEFAULT_WINDOW_SIZE = 100;
public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles,
boolean useSharedStringsTable) { this._sxFromXHash = new HashMap(); this._xFromSxHash = new HashMap(); this._randomAccessWindowSize = 100; this._compressTmpFiles = false; this._sharedStringSource = null; this.setRandomAccessWindowSize(rowAccessWindowSize); this.setCompressTempFiles(compressTmpFiles);
.......
可以通过构造函数进行修改:
public SXSSFWorkbook(int rowAccessWindowSize) { this((XSSFWorkbook)null, rowAccessWindowSize);
}
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 Android事件分发机制浅析(1)
【推荐】 从细节处谈Android冷启动优化
【推荐】 MongoDB之我是怎么成为Primary节点的
分析自己遇到的Excel导出报NullpointException问题的更多相关文章
- C# Excel导出超出65536行报错 Invalid row number (65536) outside allowable range (0..65535)
C# Excel导出超出65536行报错 Invalid row number (65536) outside allowable range (0..65535) 一:报错 Invalid row ...
- 二十六、【开源框架】EFW框架Winform前端开发之Grid++Report报表、条形码、Excel导出、图表控件
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...
- .NET Excel导出方法及其常见问题详解
摘要:.NET Excel导出方法及其常见问题详解. 一.Excel导出的实现方法 在.net 程序开发中,对于Excel文件的导出我们一共有三种导出方式: 利用文件输出流进行读写操作 这种方式的导出 ...
- 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
- 用SpringMvc实现Excel导出功能
以前只知道用poi导出Excel,最近用了SpringMvc的Excel导出功能,结合jxl和poi实现,的确比只用Poi好,两种实现方式如下: 一.结合jxl实现: 1.引入jxl的所需jar包: ...
- 在做excel导出时如何将excel直接写在输出流中
之前做excel导出时,我都是先将文件写在服务器上,然后再下载下来,后来发现原来可以直接将文件写在输出流里边. 下面是一个小demo: package com.huaqin.fcstrp.util; ...
- excel导出使用get请求参数过长问题
遇到的问题: excel导出功能时,使用的是window.location.href=url也就是get请求.当传入参数过长的时候就报了414,地址过长的错误. 解决思路: 将get请求换为post请 ...
- java利用EasyPoi实现Excel导出功能
easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 语言( ...
- js-xlsx 实现前端 Excel 导出(支持多 sheet)
之前写文章介绍了使用 js-xlsx 实现导入 excel 的功能,现在再介绍一下如何使用 js-xlsx 进行 excel 导出. [实现步骤] 1. 首先安装依赖 npm install xlsx ...
随机推荐
- Matlab多项式拟合測试
x=0:0.2:4; %生成等差数列 rnd=rand(1,size(x,2))*5; %生成一组随机数 y=x.*x.*x+x.*x+6+rnd; %生成y=x^3+x^2+6函数在垂直方向5个尺度 ...
- BUPT复试专题—分数加法(2014网研)
题目描述 求2^-a + 2^-b,其中a和b均为正整数,结果用最简分数表示 输入 第一行为测试数据的组数T (1~400).请注意,任意两组测试数据之间相互独立的.每组测试数据一行,包含两个整数a和 ...
- HTML网页之进入站点口令脚本
加入以下这个脚本在head标签中. <script language="JavaScript"> <!-- var password=""; ...
- Cocos2d-x游戏《雷电大战》开源啦!要源代码要资源快快来~~
写在前面的话:这是笔者开发的第二个小游戏<雷电大战>,之前就过这个游戏和<赵云要格斗>一样,终于将会开源. 因为自己的一些个人原因. 这个游戏还没有完毕.可是很多网友都过来寻求 ...
- 哈理工2015 暑假训练赛 zoj 2976 Light Bulbs
MS Memory Limit:65536KB 64bit IO Format:%lld & %llu SubmitStatusid=14946">Practice ...
- android 学习笔记四:控件
1.android:gravity 指定控件的基本位置,比如居中.居右等位置 Top:顶部 bottom:底部 left:居左 right:居右 center_vertical:垂直居中 center ...
- 用C++、Qt实现的小游戏2048
窗口布局与游戏截图: 实现思路: 1.使用二维数组模拟整个游戏网格,并将二维数组中每个数的大小用作游戏中每个网格中的数据. 2.将对游戏的数据及数据的操作(即玩家的操作对游戏数据的影响)作为一个类,游 ...
- dsBlog_杂类
C++,MFC的综合类的博客. 1. http://www.cnblogs.com/mfryf/category/354043.html
- GDI泄露+改EXE名
CDC 应该是成对使用 GetDC and ReleaseDC(不用new and delete) 泄露 1.改变生产exe名称:工程->设置->连接->输出文件名:Release/ ...
- MD5的学习与练习
MD5加密的Java实现 在各种应用系统中,如果需要设置账户,那么就会涉及到存储用户账户信息的问题,为了保证所存储账户信息的安全,通常会采用MD5加密的方式来,进行存储.首先,简单得介绍一下,什么是M ...