当前位置 : 首页 » 文章分类 :  开发  »  Apache-POI

Apache-POI

Apache POI 操作Excel表格笔记


tabula-java 从pdf提取表格

从 PDF 文件中进行表格抽取 (tabula || paddle-pp-structure)
https://xie.infoq.cn/article/6fa3e4ffab86202c22677ddd5

https://github.com/tabulapdf/tabula-java?tab=readme-ov-file


问题

OLE2NotOfficeXmlFileException

POI 读 excel 报错:
Caused by: org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException: The supplied data appears to be in the OLE2 Format. You are calling the part of POI that deals with OOXML (Office Open XML) Documents. You need to call a different part of POI to process this data (eg HSSF instead of XSSF)

原因:
正在尝试使用 Apache POI 库来处理一个 OLE2 格式的文件,但是你调用的却是处理 OOXML(Office Open XML)格式文档的 POI 组件。
Apache POI 是一个流行的 Java 库,用于读取和写入 Microsoft Office 文档。它支持两种主要的表格格式:

  • OLE2(也称为 HSSF):这是早期 Excel 文件格式(.xls)的基础。
  • OOXML(也称为 XSSF):这是较新的 Excel 文件格式(.xlsx)的基础,从 Excel 2007 开始引入。

报错信息中提到的“你正在调用处理 OOXML 文档的 POI 部分”意味着你可能使用了 XSSFWorkbook 或相关的 XSSF 类来打开和操作 Excel 文件,但实际上你提供的文件是一个 OLE2 格式的 .xls 文件,而不是一个 OOXML 格式的 .xlsx 文件。

解决:
提供的 excel 文档是 xls 表格,但文件后缀改成了 xlsx,导致用错 POI 方法。


Strict OOXML isn’t currently supported

读取 word 或 excel 报错:
org.apache.poi.ooxml.POIXMLException: Strict OOXML isn’t currently supported, please see bug #57699

解决:
将文档另存为重新保存下,保存为非 Strict Open XML 模式


POI 读 docx 文件报错 Zip bomb detected

dev.langchain4j.data.document.parser.apache.poi.ApachePoiDocumentParser.parse(InputStream) 内部调用 poi 读 docx 时报错

try (POITextExtractor extractor = ExtractorFactory.createExtractor(inputStream)) {
    String text = extractor.getText();
    return Document.from(text);
} catch (IOException e) {
    throw new RuntimeException(e);
}

解析 docx 报错:

java.io.IOException: Zip bomb detected! The file would exceed the max. ratio of compressed file size to the size of the expanded data.
This may indicate that the file is used to inflate memory usage and thus could pose a security risk.
You can adjust this limit via ZipSecureFile.setMinInflateRatio() if you need to work with files which exceed this limit.
Uncompressed size: 102813, Raw/compressed size: 794, ratio: 0.007723
Limits: MIN_INFLATE_RATIO: 0.010000, Entry: word/fonts/font1.odttf

原因:
docx 本质是个 zip 压缩文件,它包含了多个 XML 文件和其他媒体文件。可以通过改变文件扩展名从.docx到.zip,然后解压这个文件来查看其中的内容。
这个错误是由于 Apache POI 在处理压缩的 docx 文件时,发现压缩文件的大小和解压后的大小之比小于默认的最小比例,这可能是一个潜在的 Zip 炸弹,所以抛出了这个异常。
Zip 炸弹是一种网络攻击方式,攻击者会制作一个极小的压缩文件,但是解压后的文件却非常大,以此来消耗服务器的资源。

解决:
修改 zip 炸弹判断阈值:
ZipSecureFile.setMinInflateRatio(0);

https://stackoverflow.com/questions/44897500/using-apache-poi-zip-bomb-detected


单元格最大内容长度为32767字符错误

Excel 单元格内容最大长度为32767 (2^15-1)

java.lang.IllegalArgumentException: The maximum length of cell contents (text) is 32,767 characters
at org.apache.poi.xssf.streaming.SXSSFCell.setCellValue(SXSSFCell.java:340) ~[poi-ooxml-3.15.jar:3.15]
at com.nio.uds.job.service.ExportService.writeToWorkbook(ExportService.java:132) ~[classes/:?]
at com.nio.uds.job.DumpUserDataPulseApplication.dumpUserData(DumpUserDataPulseApplication.java:211) ~[classes/:?]
at com.nio.uds.job.DumpUserDataPulseApplication.run(DumpUserDataPulseApplication.java:134) ~[classes/:?]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:723) ~[spring-boot-1.5.12.RELEASE.jar:1.5.12.RELEASE]
… 6 more


POI 删除 doc/docx 页眉页脚

doc HWPFDocument 删除页眉页脚

InputStream inputStream = new FileInputStream("/Users/xxx.doc");
HWPFDocument hwpfDocument = new HWPFDocument(inputStream);
hwpfDocument.getFootnoteRange().delete();
hwpfDocument.getHeaderStoryRange().delete();

POI 无法读取 word 中的自动编号

比如 word 中自动编号 “第一章” 解析后的文本中没有 第一章,或者只有数字序号,需要注意。


SXSSFWorkbook 处理超大Excel

POI提供了SXSSF的方式可以流式的创建十分大的xlsx文件,SXSSF使用了window的概念,如果数据行已经超出window的范围,那么就无法修改其内容。
这个窗口的大小可以在构造函数中设定new SXSSFWorkbook(int windowSize) 也可以在sheet中设定SXSSFSheet#setRandomAccessWindowSize(int windowSize),其默认值为SXSSFWorkbook.DEFAULT_WINDOW_SIZE(100)。
还要注意SXSSF会创建一些临时文件这个需要在finally中显示地通过调用dispose方法清除,而且临时文件也占用一定硬盘,可以通过wb.setCompressTempFiles(true)设置workbook的临时文件使用压缩来减少硬盘占用。

POI-处理大EXCEL文件(XLSX写)
https://www.cnblogs.com/resentment/p/6414210.html


HSSFWorkbook/XSSFWorkbook/SXSSFWorkbook 区别

用 JavaPOI 导出 Excel 时,我们会考虑到 Excel 版本及数据量的问题。针对不同的 Excel 版本,要采用不同的工具类。

  • HSSFWorkbook 是操作 Excel2003 以前(包括2003)的版本,扩展名是.xls
  • XSSFWorkbook 是操作 Excel2007 的版本,扩展名是.xlsx
  • SXSSFWorkbook 从 POI 3.8 版本开始,提供了一种基于XSSF的低内存占用的API——SXSSFWorkbook

对于不同版本的 EXCEL 文档要使用不同的工具类,如果使用错了,会提示如下错误信息。
org.apache.poi.openxml4j.exceptions.InvalidOperationException
org.apache.poi.poifs.filesystem.OfficeXmlFileException

当数据量超出 65536 条后,在使用 HSSFWorkbook 或 XSSFWorkbook,程序会报 OutOfMemoryError:Javaheap space; 内存溢出错误。这时应该用 SXSSFWorkbook

Java基础——HSSFworkbook,XSSFworkbook,SXSSFworkbook区别简述
https://blog.csdn.net/qq_34869143/article/details/76512289


SXSSFSheet有数据但getLastRowNum值为0问题

问题:
SXSSFWorkbook 的 sheet[0] 中第一行有标题行数据,但是用 getRow() 方法取到的 Row 却为null,或者 sheet.getLastRowNum() 返回 0

原因:
不能使用 SXSSFWorkbook 读取 excel 数据,要用 XSSFWorkbook 读取数据!
SXSSFWorkBook is write only, it doesn’t support reading

SXSSF 可以解决写大文件的问题,但是无法进行修改文件原有的内容,也不支持读源文件。如果需要,可以结合之前的读大文件,然后将读到的内容通过SXSSF写入新的文件,来达到类似修改的操作。

Sheet sheet = wb.getSheetAt(0);
int lastRowNum = sheet.getLastRowNum(); // 结果是 0
Row row = sheet.getRow(0); // 结果是 null

官方文档在 SXSSFWorkbook 的构造方法中明确说了 不支持访问和修改已有的行
public SXSSFWorkbook(XSSFWorkbook workbook)
Construct a workbook from a template.

There are three use-cases to use SXSSFWorkbook(XSSFWorkbook) :

  • Append new sheets to existing workbooks. You can open existing workbook from a file or create on the fly with XSSF.
  • Append rows to existing sheets. The row number MUST be greater than max(rownum) in the template sheet.
  • Use existing workbook as a template and re-use global objects such as cell styles, formats, images, etc.

All three use cases can work in a combination.

What is not supported:

  • Access initial cells and rows in the template. After constructing all internal windows are empty and SXSSFSheet.getRow(int) and SXSSFRow.getCell(int) return null.
  • Override existing cells and rows. The API silently allows that but the output file is invalid and Excel cannot read it.

https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/streaming/SXSSFWorkbook.html#SXSSFWorkbook-org.apache.poi.xssf.usermodel.XSSFWorkbook-

之前我想写一个这样的方法,将rows写入一个已存在的 SXSSFWorkbook ,方法里面先调用 getLastRowNum() 来获取表格中已有的行数,好多情况下获取不到或不准,现在知道了不能这样写,应该用一个全局变量保存已写入的行数。

/**
 * 将行数据写入Workbook
 * @param wb
 * @param rows
 * @return
 */
private void writeToWorkbook(Workbook wb, List<List<String>> rows) {
    // 获取sheet
    Sheet sheet = wb.getSheetAt(0);
    int lastRowNum = sheet.getLastRowNum(); //经常为0

    // 写入excel
    for (int i = 0, rowCount = rows.size(); i < rowCount; i++) {
        Row row = sheet.createRow(lastRowNum++);
        List<String> rowData = rows.get(i);
        for (int j = 0, colCount = rowData.size(); j < colCount; j++) {
            logger.info(rowData.get(j));
            row.createCell(j).setCellValue(rowData.get(j));
        }
    }
}

改成下面这样写就好了,多一个起始行数参数:

/**
 * 将行数据写入Workbook
 * @param wb
 * @param lastRowNum wb中已有行数
 * @param rows
 */
private int writeToWorkbook(Workbook wb, int lastRowNum, List<List<String>> rows) {
    // 获取sheet
    Sheet sheet = wb.getSheetAt(0);

    // 写入excel
    for (int i = 0, rowCount = rows.size(); i < rowCount; i++) {
        Row row = sheet.createRow(lastRowNum++);
        List<String> rowData = rows.get(i);
        for (int j = 0, colCount = rowData.size(); j < colCount; j++) {
            logger.info(rowData.get(j));
            row.createCell(j).setCellValue(rowData.get(j));
        }
    }
    return lastRowNum;
}

POI-处理大EXCEL文件(XLSX写)
https://www.cnblogs.com/resentment/p/6414210.html

Read xlsx file with POI (SXSSFWorkbook)
https://stackoverflow.com/questions/13873489/read-xlsx-file-with-poi-sxssfworkbook

Reading data from xlsx with Apache POI’s SXSSFSheet
https://stackoverflow.com/questions/12513981/reading-data-from-xlsx-with-apache-pois-sxssfsheet

Apache POI getRow() returns null and .createRow fails
https://stackoverflow.com/questions/30868325/apache-poi-getrow-returns-null-and-createrow-fails

SXSSFWorkbook XSSFWorkbook 我所遇到的坑大集合,希望能帮助更多的人。
https://blog.csdn.net/qq_31615049/article/details/82228812

使用poi读取excel时,getRow()方法返回null
https://www.cnblogs.com/study-room/p/5459363.html

SXSSFSheet对象调用getLastRowNum的问题
https://blog.csdn.net/zc123456zzc/article/details/47301461


常用类

Class XSSFWorkbook
https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/usermodel/XSSFWorkbook.html

Class SXSSFWorkbook
https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/streaming/SXSSFWorkbook.html

Class SXSSFSheet
https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/streaming/SXSSFSheet.html


上一篇 Java-File

下一篇 Apache-Curator

阅读
评论
2.1k
阅读预计10分钟
创建日期 2019-01-02
修改日期 2024-10-10
类别

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论