java poi分批导入_Java批量爬取Excel数据,poi简易新手教程,3.9稳定版本
发布日期:2021-06-24 16:29:03 浏览次数:2 分类:技术文章

本文共 2883 字,大约阅读时间需要 9 分钟。

最近看我老婆经常加班,工作辛苦,实在于心不忍,于是就了解了一下她的工作内容。

原来她经常要花好几个小时,从数十个甚至数百个Excel文件里提取数据,整理成文档,而这些Excel都是一些根据模板文档填写内容的报告,也就是格式都相同的,只是每个内容不同而已。

这种批量重复的工作,人工效率很低,最适合程序来跑了。

于是,我就帮我老婆写了个小程序,顺便把过程记录下来,作为一个Java爬取Excel的入门教程,分享给大家。

起初,我使用的Java库是jxl,它一个比较常用的Excel处理库。但是我发现文件夹里虽然给的是格式文档,里面内容基本是一样的,但是由于被不同的人保存后,存在部分人把文档格式由xls改成了xlsx,而jxl比较古老,只支持xls文档的处理,出于对兼容性的考虑,我放弃了jxl,采用poi来处理这些文档。

net.sourceforge.jexcelapi

jxl

2.6

jxl2.6是一个比较稳定的版本,也是我常用的一个版本。下面是poi的版本,我起初就是随便百度的,用的3.15版本,但是发现和jdk10有一些不兼容的地方,后来又试了4.1.2最新的版本,但是神奇的是怎么也找不到要用的类。

几经周折,我最后选用了网上公认最稳定的版本3.9,不同的版本之间还是有很多差异化,以我的个人体验来说,都不是特别完善,比如3.15版本有获取全部分页的函数,3.9版本反而没有了,4.1.2又有了。不过这个不重要,可以自己重写一个方法就可以获得指定分页。

org.apache.poi

poi

3.9

org.apache.poi

poi-ooxml

3.9

第一步,在pom里加入版本依赖,现在基本都是Maven快速开发了,如果你还没有Maven,那就只能自己下载到自己的lib库里了。

第二步,获得Excel文件,并转化成文件流,以此来获得workbook。这个rwb可以理解为整个Excel对象。

val fis = FileInputStream(file)

// xlsx文件处理

val rwb = if (file.name.contains(".xlsx")) {

XSSFWorkbook(fis)

}

// 普通xls格式文件

else {

HSSFWorkbook(fis)

}

第三步,根据分页特征,获得指定分页,比如含有“立项书”字样,因为原生的函数并不具备这个功能,原生函数只能获得“立项书”分页,不能获得例如“项目立项书”等其他含有关键字的分页。

718b17782b80

image.png

于是我就自己写了一个函数,来获取含有指定特征分页列表。

/**

* 获取含有特征的分页

*/

fun getSheetsByKeyword(rwb: Workbook, keyword: String): List {

return (1..rwb.numberOfSheets).map { rwb.getSheetAt(it - 1) }.filter { sheet -> sheet.sheetName.contains(keyword) }

}

不得不说,kotlin真的强大,这么复杂的操作,一句话就搞定了,把效率和代码的简洁优雅发挥到了极致,如果换成传统的Java来写,代码要更臃肿的多。

拿到需要爬取数据的分页后,就是简单的提取数据了,一般最简单的操作就是指定格子提取数据。

比如提取G4的数据,那转换成代码就是row: 3, column: 6,因为数据都是从0开始计数,由于sheet里也没有了以前直接提取坐标数据的函数,改成了分两步提取,先获得行,在获取指定列数据。同时需要注意一点,Excel数据单元格类型一定要区分,不然读取数据会报错。

// 获得G4数据

sheet.getRow(3).getCell(6).let {

when (it.cellType) {

Cell.CELL_TYPE_STRING -> println(it.stringCellValue)

Cell.CELL_TYPE_NUMERIC -> println(it.numericCellValue)

}

}

如果只有一个两个数据,直接写代码是很简单的,如果是十几个,甚至数百个数据,如果全用代码维护起来也不容易,一方面冗余代码非常多,一方面破坏了代码的开闭原则,因为我们后期要尽量不通过修改代码来达到需求修改的目的。

所以我把指定格子这部分代码提取出来,作为一个配置来引入。

我先简单做个示范,比较偷懒的方法是指定一个Map,当然最好是用配置文件来导入,这样就不用动代码了,但是导入后的原理是一样。这个Map定义了导出后每个标题对应的格子坐标。

/**

* 指定读取单元格位置

*/

val cellMap = mapOf(

"项目名称" to Pair(3, 6), // G4

"项目经理" to Pair(5, 8), // I6

"立项时间" to Pair(3, 4), // E4

"入场时间" to Pair(14, 0), // A15

"项目周期" to Pair(14, 2), // C15

"计划工作量" to Pair(25, 2), // C26

"策划" to Pair(16, 1), // B17

"需求" to Pair(17, 1), // B18

"设计" to Pair(18, 1), // B19

"编码" to Pair(19, 1), // B20

"测试" to Pair(20, 1), // B21

"上线" to Pair(21, 1), // B22

"验收" to Pair(22, 1), // B23

"维保" to Pair(23, 1) // B24

)

Ok,假设有这样一个Map之后,就可以根据坐标去捕捉数据了,这样后期维护多一个坐标,少一个坐标,都不会影响代码的稳定性。

cellMap.forEach { cellPos ->

val key = cellPos.key

val row = cellPos.value.first

val column = cellPos.value.second

sheet.getRow(row).getCell(column).let {

when (it.cellType) {

Cell.CELL_TYPE_STRING -> resultMap[key] = it.stringCellValue

Cell.CELL_TYPE_NUMERIC -> resultMap[key] = it.numericCellValue

}

}

}

这样就可以爬取到Excel大部分的数据了。

值得注意的一点,Excel的单元格如果是日期,爬取后则会变成数字,需要在写入后对单元格进行格式设置,才会重新变成日期。这是因为Excel的机制引起的,保存的日期其实是指定时间到这个日期的天数,所以是数字,一开始都给我搞蒙了,一直以为导错了数据。

转载地址:https://blog.csdn.net/weixin_33826897/article/details/114689212 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:java引入bean代码_Spring装配Bean之Java代码装配bean
下一篇:中兴java翻盖_颠覆全面屏!中兴双屏折叠手机AXON M真机图赏:PC级体验

发表评论

最新留言

很好
[***.229.124.182]2024年04月25日 02时07分44秒