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

Apache-POI

Apache POI 操作Excel表格笔记


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

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


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


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;

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

SXSSFWorkbook
从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的API——SXSSFWorkbook

当数据量超出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

阅读
评论
1.7k
阅读预计8分钟
创建日期 2019-01-02
修改日期 2024-03-06
类别

页面信息

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

评论