网站首页 > 技术文章 正文
作者:khotyn 来源:https://blog.khotyn.com/blog/2013/03/01/apache-poi-notes/
最近在写一个解析 Excel 的程序,需要把从前端上传上来的 Excel 程序解析成 JSON 格式返回给前端,期间也试过 jxl ,不过它只支持到 Excel 2003。后来转而使用 apache 的 POI,作为初次使用者,使用过程中遇到了不少的问题:
# 如何引入 XSSF
刚下手写的时候,直接使用了 HSSFWorkbook 处理 Excel,后来发现它只能处理 2003 的 Excel,而不能处理 2007 版本的 Excel,翻了一下 POI 的文档,发现处理 2007 的 Excel 需要使用 XSSFWorkbook,但是引入的 POI 包中却找不到 XSSF 相关的类,原猜想是因为引入了版本较新的 POI,而官方的文档还是比较老的,因而被误导。结果发现使用 XSSF 需要额外引入 poi-ooxml 这个 jar 包, XSSF 相关的类都在这个 jar 包中,mvn 依赖如下:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency>
# 兼容处理 Excel 2003 和 2007
引入了 poi-ooxml 以后就使用 XSSF 来处理,本以为 XSSF 既然能够处理 Excel 2007,那么 2003 也该能处理吧?得向下兼容不是?没想到不行!总不能用扩展名来区别是 2003 还是 2007 吧,后来发现了 WorkbookFactory 这个类,它的 create(InputStream inp) 方法可以根据版本来选择创建 HSSFWorkbook 还是 XSSFWorkbook,使用者无需关心版本的问题,非常方便!
# 以 String 的形式读取单元格的数据
要读取的 Excel 中有一些数据是数字的,单元格的类型是 Numberic 的,而我希望将单元格中的数据都以 String 的形式拿出来。于是当我看到 Cell.getStringCellValue() 这个方法的时候满心欢喜,但是当用了之后,这货居然直接给我一个异常,定眼一样,这方式是 getStringCellValue,而不是 getCellStringValue,真是瞎了眼了。
事实上,Cell 也根本没有 getCellStringValue 这样的方法,后来借助了 SOF,查到了一个方法:
row.getCell(j).setCellType(Cell.CELL_TYPE_STRING); cellValue = row.getCell(j).getStringCellValue();
是的,就是先把单元格变成 String 类型的,然后再调用 getStringCellValue() 来获取数据,虽然这方法可行,但是总感觉有点猥琐,不知大家有没有更好的方法?
错误地使用 getPhysicalNumberOfCells()
遇到的最后一个坑就是使用了 getPhysicalNumberOfCells() 这个方法来获取一行中单元格的数量以对行的中单元格进行遍历,依靠这个方法来遍历会出现的情况就是如果行中间的某些单元格是空的,那么你就解析不到这一行最后的几个单元格,原因是因为按照文档的说明
Gets the number of defined cells (NOT number of cells in the actual row!). That is to say if only columns 0,4,5 have values then there would be 3.
这个方法只对有值的单元格进行计数,正确的遍历方法应该用 getFirstCellNum() 和 getLastCellNum() 来确定第一个单元格和最后一个单元格的位置,然后进行遍历,当然,要注意中间可能会出现空单元的情况,小心 NPE 异常。
另外,我发现很多 POI 的中文介绍资料上遍历 Excel 的样例代码都是采用了 getPhysicalNumberOfCells(),估计作者也没有经过彻底的测试,或者仔细阅读官方的文档和例子,平时大家做开发的时候,还是尽量找官方的介绍资料为好,看二手资料,一不小心就踩坑了。
猜你喜欢
- 2024-10-02 MySQL用的再溜,不知道业务如何设计也白搭!!!
- 2024-10-02 JShaman本地部署专业版,批量加密工具「源码」
- 2024-10-02 UWP 自定义密码框控件(uwp+自定义密码框控件怎么用)
- 2024-10-02 干货-带你总结Mysql相关优化(mysql常用优化方案)
- 2024-10-02 Redis全文搜索教程之创建索引并关联源数据
- 2024-10-02 PHP数据类型与常量(php的数据类型主要有哪几种?)
- 2024-10-02 TensorFlow2学习25、TF2.0使用YoloV3
- 2024-10-02 Java对象内存布局(java对象在内存中如何存储)
- 2024-10-02 PHP手机和身份证号打码,生成随机数,判断逗号隔开的数字串等
- 2024-10-02 杀死僵尸进程,你需要这些神奇高效的Linux命令行
- 1509℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 527℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 492℃MySQL service启动脚本浅析(r12笔记第59天)
- 472℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 469℃启用MySQL查询缓存(mysql8.0查询缓存)
- 450℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 429℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 426℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)