需求概要
最近接到一个需求,概要来讲就是实现百万级数据导出Excel,并根据其中的数据项自动生成折线图等图表。经技术调研,针对内存、性能等要素,Apache POI此技术可完成此需求。
Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式文件读和写的功能。 .NET的开发人员则可以利用NPOI(POI for .NET)来访问POI的功能。
总结构
- HSSF - 提供读写Microsoft Excel XLS 格式文件的功能。
- XSSF - 提供读写Microsoft Excel OOXML XLSX 格式文件的功能。
- HWPF - 提供读写Microsoft Word DOC 格式文件的功能。
- XWPF - 提供读写Microsoft Word DOCX 格式文件的功能。
- HSLF - 提供读写Microsoft PowerPoint格式文件的功能。
- HDGF - 提供读Microsoft Visio格式文件的功能。
- HPBF - 提供读Microsoft Publisher格式文件的功能。
- HSMF - 提供读Microsoft Outlook格式文件的功能。
结构图
Apache POI发行版支持多种文档文件格式。这种支持在几个Jar文件中提供。并不是每种格式都需要所有的Jar。下表显示了POI组件、Maven存储库标记和项目的Jar文件之间的关系。
组件 | 应用类型 | Maven 工件名 |
---|---|---|
POIFS | OLE2 Filesystem | poi |
HPSF | OLE2 Property Sets | poi |
HSSF | Excel XLS | poi |
HSLF | PowerPoint PPT | poi-scratchpad |
HWPF | Word DOC | poi-scratchpad |
HDGF | Visio VSD | poi-scratchpad |
HPBF | Publisher PUB | poi-scratchpad |
HSMF | Outlook MSG | poi-scratchpad |
DDF | Escher common drawings | poi |
HWMF | WMF drawings | poi-scratchpad |
OpenXML4J | OOXML | poi-ooxml plus either poi-ooxml-lite or poi-ooxml-full |
XSSF | Excel XLSX | poi-ooxml |
XSLF | PowerPoint PPTX | poi-ooxml |
XWPF | Word DOCX | poi-ooxml |
XDGF | Visio VSDX | poi-ooxml |
Common SL | PowerPoint PPT and PPTX | poi-scratchpad and poi-ooxml |
Common SS | Excel XLS and XLSX | poi-ooxml |
该表将工件映射到jar文件名中。“版本yyyymmdd”是POI版本戳。
Maven 工件名 | 先决条件 |
---|---|
poi | log4j 2.x, commons-codec, commons-collections, commons-math3 commons-io |
poi-scratchpad | poi |
poi-ooxml | poi, poi-ooxml-lite, commons-compress, SparseBitSet xmlgraphics-commons rototor graphics2d |
poi-ooxml-lite | xmlbeans |
poi-examples | poi, poi-scratchpad, poi-ooxml |
poi-ooxml-full (known as ooxml-schemas) | xmlbeans xmlsec, slf4j-api |
Zaxxer SparseBitSet被添加为POI 4.1.2中的依赖项
在POI 5.1.0中添加了Apache commons io作为依赖项
问题:
1.利用poi生成excel折线图,图无法在office excel中显示【发现...中的部分内容有问题。是否让我们尽量尝试恢复?如果您信任此工作簿的源,请单击“是”】
排查问题发现:Office Excel版本为最新:(现版本为MS 365系列,Excel版本为2311.)而Apache POI相关依赖过旧,更新为最新依赖,则排除此问题。
2.【ERROR】apache POI java.lang.NoClassDefFoundError: org/apache/commons/compress/archivers/zip/ZipFile
调整相关依赖版本为最新:
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-lite</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-full</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.25.0</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>5.2.0</version>
</dependency>
3.大量数据导出注意使用SXSSFWorkbook处理Excel文件(.xlsx)的工作簿
- XSSFWorkbook:XSSFWorkbook是POI中的XLSX格式(Excel 2007及更高版本)的工作簿实现。它使用XML文件格式存储数据,并且在内存中将整个工作簿加载到内存中进行操作。这意味着对于大型或复杂的Excel文件,可能会占用大量的内存。
- SXSSFWorkbook:SXSSFWorkbook是POI中的SXSSF流式工作簿实现。它专为处理大型Excel文件而设计,并通过限制内存使用来提供更好的性能和可伸缩性。它使用一种称为流式写入(Streaming Write)的技术,在内存中只保留一部分数据,然后将其写入硬盘,以便在需要时释放内存。
主要区别:
- 内存占用:XSSFWorkbook会将整个工作簿加载到内存中,而SXSSFWorkbook只保留部分数据,将剩余数据写入硬盘。
- 性能和可伸缩性:SXSSFWorkbook在处理大型Excel文件时可以获得更好的性能和可伸缩性,因为它可以有效地处理大量数据而无需消耗大量内存。
- 使用场景:如果处理的Excel文件较小或简单,可以使用XSSFWorkbook。如果需要处理大型Excel文件或需要更好的性能和可伸缩性,则可以考虑使用SXSSFWorkbook。
总之,XSSFWorkbook适用于较小的Excel文件,而SXSSFWorkbook适用于大型或复杂的Excel文件。选择哪个取决于具体需求和资源限制。当然亦可选取学习成本更低且对内存消耗更低的EasyExcel实现大数据导出。
4.【ERRO】Exception in thread "Thread-0" org.apache.poi.ooxml.POIXMLException:org.apache.poi.openxml4j.exceptions.InvalidOperationException: You can't add a part with a part name derived from another part ! [M1.11]
注意POI中XSSFWorkbook不可采用多线程写入不同sheet:
5.SXSSFDrawing不可生成Chart图表,
XSSFDrawing可实现此功能。
SXSSFDrawing
是Apache POI库中的一种轻量级方式来处理大型Excel文件,它主要用于写入和操作Excel文件,而不是生成图表。可以使用XSSFWorkbook
和XSSFSheet
类来创建图表,并使用相应的数据填充图表。
6.SXSSFWorkbook的close和dispose
Apache POI库中的SXSSFWorkbook(Streaming Usermodel for Excel)是一种用于处理大型Excel文件的类,特别适用于内存有限的情况。它通过限制在内存中保持的数据行数来实现流式写入。
1. `close()`方法:
- 当你完成对工作簿的所有操作后,应调用`close()`方法。此方法会将任何未写出到磁盘的剩余数据强制写出,并关闭所有相关的资源,如临时文件等。
- 如果不调用`close()`,可能会导致部分数据未被正确保存到输出文件,或者占用的系统资源没有被释放。
2. `dispose()`方法:
- 在POI 5.0.0版本之后,SXSSFWorkbook引入了`dispose()`方法作为替代`close()`的方法。
- `dispose()`方法同样用于清理和关闭SXSSFWorkbook对象,确保所有数据都被妥善地写出,并释放与之关联的资源。
- 官方推荐使用`dispose()`而不是`close()`,因为`dispose()`在内部会更彻底地清理资源,特别是对于SXSSF工作簿来说,可以更有效地管理其使用的临时文件。
总结:在使用完SXSSFWorkbook后,建议调用`dispose()`方法以确保所有数据被正确写入并释放资源。在旧版本POI中如果不存在`dispose()`,则应该调用`close()`。
7.利用XSSFWorkbook生成图表,导致系统堆内存剧增
- org.apache.xmlbeans.impl.store.ElementXobj 347,831,616 B (21.1%) 3,623,246 (11.1%)
- org.apache.xmlbeans.impl.store.AttrXobj 314,479,968 B (19%) 3,275,833 (10%)
- byte[] 286,741,680 B (17.3%) 5,227,004 (15.9%)
经过研究POI API文档发现,SXSSFWorkbook可利用getXSSFWorkbook方法获取XSSFSheet,之前由于不了解POI,为了利用XSSFSheet生成图表,竟然玩起了俄罗斯套娃,将SXSSFWorkbook写入ByteArrayOutputStream流中,再通过构造器new XSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()))获取XSSFWorkbook对象,进而生成图像,导致JVM堆内存剧增!
致使内存剧增的代码:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
wb.write(baos);
} catch (IOException e) {
e.printStackTrace();
}
try {
xssfWB = new XSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
for (DeviceInfoBO item : deviceInfoBOList) {
XSSFSheet xssfSheet = xssfWB.getSheet(item.getSheetName());
//TODO 生成图表
}
return new SXSSFWorkbook(xssfWB);
} catch (IOException e) {
e.printStackTrace();
}
优化后的代码:
XSSFSheet xssfSheet = wb.getXSSFWorkbook().getSheet(deviceInfoBO.getSheetName());
//TODO 生成图表
优雅从不过时~
效果图:
参考资料:
Apache POI简介https://en.wikipedia.org/wiki/Apache_POIApache POI官网https://poi.apache.org/index.htmlApache POI官网代码示例https://svn.apache.org/repos/asf/poi/trunk/poi-examples/src/main/java/org/apache/poi/examples/
stackoverflow相关BUG解决https://stackoverflow.com/questions/52381075/apache-poi-java-lang-noclassdeffounderror-org-apache-commons-compress-archivers