java判断excel是否打开_POI读写Excel精品指南

java判断excel是否打开_POI读写Excel精品指南_第1张图片

简介

Excel读写是我们在工作中经常会遇到的问题,因此掌握如何用Java语言操纵Excel就变得尤为重要。曾经有两个开源工具都为了解决这一问题而大放异彩,那就是POI和jxl。

当年jxl以操作便利深受笔者的喜爱,但后来由于某些原因,该项目于2009年左右最终定格在了2.6.12的版本。而POI背靠Apache的大树则一路发展到了现在,目前已经到了4.1.1的版本。

因此,现在要读写Excel基本上只有POI这一个工具可选。不过POI在操纵Excel(实际上还支持Word、Powerpoint、Outlook、Visio等)上的强大功能,是绝不会让你失望的。 a040d0454c51d6a6b8755876d0a5f056.png

注:本文以Excel2010为例进行测试,在后续版本的Excel中,部分功能可能会略有不同。)

1

读写Excel的三种方式

POI有三种类型的Excel读写API: 1) POIFS支持读写非XML格式存储的Excel文件。 2) HSSF 支持读写Excel97-2003格式(BIFF8)的文件。 3) XSSF
支持读写Excel2007+格式(OOXML)的文件。 本文仅关注目前主流的XSSF读写API。 aab8619ccef19878a1a43812c5d8a16f.png

2

Excel文档对象模型

无论POI的官方文档还是网上各种文章,均未对POI的Excel文档对象模型有过详细的描述,而笔者认为,这是理解和使用POI的关键所在,因此便有了下面这张自制的图表。从图中我们看到,可以把一个Excel文件看作一本书,书中的每一页是一个Sheet,页面上的一行相当于一个Row,而单元格则可以类比于一行中的每一个字。

java判断excel是否打开_POI读写Excel精品指南_第2张图片

具体说明如下: 1)  一个Excel文件就是一个XSSFWorkbook对象。 2) Excel里每一个Sheet都对应一个XSSFSheet对象。 3) Excel的Sheet里每一行数据为一个XSSFRow对象。 4) 每一行里的一个单元格是XSSFCell对象。 5) 每一个单元格有地址、类型、值、公式等属性。 6) 条件格式记录在XSSFSheet上,对应XSSFContitionalFormat集合,里面是具体的条件格式。条件格式应用在区域CellRangeAddress上。 7) 区域CellRangeAddress用起始和结束行号、列号来标识,所有的数字下标都从0开始计数。 8) 单元格或行样式记录在XSSFWorkbook上,会有一个样式表保存所有的样式,相同的样式在样式表中只出现一次。样式可以应用到XSSFRow或XSSFCell上面。 aab8619ccef19878a1a43812c5d8a16f.png

3

应用详解

(一)读取

在读取Excel文件时需要注意,POI提供了按Sheet名称或下标获取Sheet的方法,但是却没有提供一个遍历器,因此如果要遍历所有Sheet只能自己先获取Sheet数量再循环处理。同样的POI对于行和列也没有提供遍历器。下面的例子遍历Excel的全部Sheet并打印所有单元格内容:

java判断excel是否打开_POI读写Excel精品指南_第3张图片

在这里有几个“坑”需要提醒大家注意:

1)意在代码中对获取到的每一行或单元格有一个非空判断。如果Excel中某一行或单元格没有输入过任何内容,那么获取到的对象就是null,如果不做判断则会抛出空指针异常。

2)getFirstRowNum方法用于获取第一个有效行,该行未必是Excel文件的第一行,举例来说:如果Excel文件的前3行未输入过内容,从第4行开始才有内容,则该方法获取到的数字为3,其它类似方法同理。

3)请注意我在打印每个单元格内容时直接使用了toString方法,实际上XSSFCell对象有getStringStringCellValue、getNumericCellValue等指定具体类型的方法。但在使用这些方法时必须确保单元格类型与方法一致,否则会抛出异常。

4)XSSFCell还提供了getRawValue方法。该方法看起来很保险但实际上也有坑。例如:如果单元格内容是文本,那么该方法返回的是一个从0开始的数字编号。Excel的OOXML格式实际上把所有的文本放在了一个列表中,根据这个编号去列表中才能拿到实际的文本(XSSFWorkbook对象的getSharedStringSource方法可以返回这个列表)。

(二)写入

写入Excel文件需要依次创建各级对象,然后调用各级add方法来实现。其中每一个Sheet、Row、Cell、Style均需要创建并设置,例如下面的代码生成了一个九九乘法表:

java判断excel是否打开_POI读写Excel精品指南_第4张图片

在生成Excel时同样有一些注意事项。例如:

1)在创建CellStyle时,建议同样的样式不要重复创建,如图中注释掉的代码,否则将会创建很多实际上重复的样式,无意义地增大了文件体积。

2)添加公式、批注、错误值、超链接等需要用相应的方法,本文中未做赘述。

3)常用的自动调整列宽操作较为耗时,建议仅在最后执行一次。

(三)复制

在实际应用中,经常是先制作一个Excel模板,设置好格式、公式等内容后,用“占位符”标识要写入具体数据的位置,然后再通过Java程序读取占位符并替换为具体的数据来生成一个新的文件。这就涉及到复制现有Excel文件内容到一个新文件中。下面分别从内容样式和条件格式两个方面分别进行讲解: 1. 单元格内容及格式复制 在复制过程中,POI的Excel文档对象模型的概念体现得非常清楚,下面我们还是通过一个例子来演示一下如何从一个Excel文件中复制单元格到另一个Excel文件:

java判断excel是否打开_POI读写Excel精品指南_第5张图片

特别需要注意的是:

1)单元格的四个基本属性:类型、值、格式和批注需要使用不同的方法分别复制。

2)请注意第4行被注释的代码,如果采用这样的复制方式,那么只有源单元格和目标单元格在同一个Excel文件(XSSFWorkbook对象)中时才会成功,否则会发生运行时错误。因为样式是“属于”一个Book的,一个样式不能有两个“主人”。所以跨Excel文件复制时,需要采用克隆的方式新建一个样式。

3) POI没有自动判断单元格类型并复制值的方法,因此为了避免单元格小绿三角(文本存储的数值)类似的错误,需要指定单元格类型再设置单元格值,此时就需要针对不同的单元格类型调用不同的设置方法。

2.条件格式复制

条件格式是依附在XSSFSheet上的对象,它有几个基本属性组成:应用范围、类型、公式、格式等。我们同样通过代码来演示其使用,不过由于此部分比较复杂,我们将代码分成几个部分来看。

首先看一下整体代码框架

java判断excel是否打开_POI读写Excel精品指南_第6张图片

特别需要注意的是:

1)首先要从Sheet上获取全部的条件格式集合。

2)注意在外层循环中被注释的那行代码,编译及运行不会报错,看起来是很简洁的方式,但是这样生成的文件在打开时会报“文件损坏”,修复后尝试复制的条件格式会全部丢失。究其原因,还是因为“别人的”条件格式不能直接拿来当“自己的”。

3)在条件格式集合里会分成很多的规则(Rule),需要自己循环遍历每个规则并复制格式,具体的操作分成了3个步骤,既三个TODO标签,后续分别展开说明。

现在让我们看一下如何复制条件格式规则:

java判断excel是否打开_POI读写Excel精品指南_第7张图片

特别需要注意的是:

1)POI没提供一个统一且便利的方法直接clone一下,需要按照不同的条件格式类型来进行复制,上面的代码展示了每一种类型需要设置的全部充要方法。

2)POI提供了一种称为过滤器(FILTER)的类型,但是实际上Excel本身没有这种条件格式,因此POI也没有且无法实现这种类型对应的方法。

再来看一下格式复制:

java判断excel是否打开_POI读写Excel精品指南_第8张图片

特别需要注意的是:

1)由于需要对条件格式规则按照不同类型进行生成,因此在开始复制格式之前,必须先确保规则(newRule)创建成功不能为null。

2)Excel可以设置的条件格式有四种:数字格式、字体、边框和填充。但是POI未能实现数字格式的条件格式设置,对于其它三种需要分别进行复制。

3)对于字体格式,Excel支持删除线样式,但是POI未能实现。另外,Excel不支持条件格式设置上下标,但是POI却提供了相应的setEscapementType方法,毫无疑问该方法的执行是不会有结果的。

4)填充格式设置提供了两类方法:填充样式和填充色。在进行填充样式复制时必须先进行是否NO_FILL判断,如果不判断直接复制不会报错,但是运行后自动变成黑色填充。

5) 填充格式对于前景色和背景色的设置方法必须进行非空判断,否则可能产生运行时异常。

6)复制边框格式提供了N多方法,但只需要使用示例代码中的部分即可。特别的,POI似乎未能实现复制边框颜色的相应功能。

最后应用条件格式就变得非常简单:

7c3733c57edfd2e73c2a478a6d75f3be.png

只需要将前面创建好的样式,添加到新Excel的条件格式中即可。注意因为此处是原样复制,所以该方法的第一个参数就直接获取了源Excel中条件格式应用的区域范围。如果是按照Excel模板来生成新的文件,那么原来的一行可能会由于数据不同而扩展为多行,此时就需要去构造一个新的范围,在此新范围上应用条件格式。简单示例代码如下:

cbda829e7775b785ede6d649cc5a0f7d.png

aab8619ccef19878a1a43812c5d8a16f.png

java判断excel是否打开_POI读写Excel精品指南_第9张图片

4

总结

POI在操纵Excel文件方面的确提供了非常强大的功能,但是可能由于种种原因,在应用时也有不少坑存在,如何填坑经常是网上的常见问题。在充斥网络上的各种复制粘贴的文章中,我们经常很难找到需要的信息。

本文立足于解决Excel读写过程中遇到的各种常见问题,以POI官网信息为引子,同时以源代码阅读作为辅助,编制并测试了各种典型的示例代码,希望对大家以后应用POI有所帮助。

参考资料:

[1] https://poi.apache.org

你可能感兴趣的:(java判断excel是否打开,用poi将excel解析成对象)