apache.poi读取.xls文件时The content of an excel record cannot exceed 8224 bytes

目录

问题描述

使用apache.poi读取.xls文件时有The content of an excel record cannot exceed 8224 bytes的报错。待读取的文件的内容也是通过apache.poi写入的,我的文件修改步骤是先删除页签然后写入页签(页签名是保持不变的),这样一次修改的结果也是符合我的预期的,但是某次程序读取文件时就出现了下面的报错,而且手动也打不开文件了。

java 复制代码
Exception in thread "main" org.apache.poi.util.RecordFormatException: The content of an excel record cannot exceed 8224 bytes
	at org.apache.poi.hssf.record.RecordInputStream.nextRecord(RecordInputStream.java:222)
	at org.apache.poi.hssf.record.RecordFactoryInputStream.nextRecord(RecordFactoryInputStream.java:253)
	at org.apache.poi.hssf.record.RecordFactory.createRecords(RecordFactory.java:494)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:356)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:413)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:394)
	at com.mark.learning.bug.excel.ExcelXls.addSheet(ExcelXls.java:28)
	at com.mark.learning.bug.excel.ExcelXls.main(ExcelXls.java:84)

版本

xml 复制代码
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>

定位:打印size最大的Record

既然提示某一个Record超过了上限了,那我就把这个内容打印出来看看。最新定位到ExternSheetRecord 类的_list属性。

java 复制代码
第267个record的size:6066
[EXTERNSHEET]
   numOfRefs     = 1010
refrec         #0: extBook=0 firstSheet=-1 lastSheet=-1
refrec         #1: extBook=0 firstSheet=-1 lastSheet=-1
refrec         #2: extBook=0 firstSheet=-1 lastSheet=-1
refrec         #3: extBook=0 firstSheet=-1 lastSheet=-1
refrec         #4: extBook=0 firstSheet=-1 lastSheet=-1
refrec         #5: extBook=0 firstSheet=-1 lastSheet=-1
java 复制代码
public class ExternSheetRecord extends StandardRecord {

    public final static short sid = 0x0017;
	private final List<RefSubRecord> _list;//这里有很多的记录信息

定位:RefSubRecord

RefSubRecord记录是什么信息?什么时候进行初始化?我在构造函数打了一个断点,发现每当删除一个页签或者新增一个页签就会创建RefSubRecord页签

这里有意思的是删除页签的时候会把对应索引的记录的firstSheetIndexlastSheetIndex修改为-1。但是后面新增的从时候又尝试根据这两个变量找到对应的索引


这样就导致到了ExternSheetRecord 类的_list属性会随着程序的运行不断的增长!

解决

1.直接替换文件类型将.xls换位新版的.xlsx

2.升级版本apache.poi版本,我尝试升级为3.8版本的时候发现就没有这个问题了,原因是再3.8中删除的删除的页签的时候不会修改RefSubRecord的信息
3.17的删除逻辑

3.8的删除逻辑 (少了上面红框的内容)

代码

复现...exceed 8224 bytes报错的代码

java 复制代码
public class ExcelTest {

    private static int createSheetCnt = 0;
    private static final String path = "C:\\Users\\Desktop\\test2.xls";

    public void addSheet() {
        try {
            File file = new File(path);
            FileInputStream in = new FileInputStream(file);
            HSSFWorkbook workbook = new HSSFWorkbook(in);
            in.close();

            String sheetName = "test";
            int sheetIndex = workbook.getSheetIndex(sheetName);
            if (sheetIndex >= 0) {
                //页签存在删除页签
                workbook.removeSheetAt(sheetIndex);
            }
            //新建一个页签写入文件
            workbook.createSheet(sheetName);
            FileOutputStream fileOut = new FileOutputStream(path);
            workbook.write(fileOut);
            fileOut.close();

            System.out.println("创建页签次数:" + ++createSheetCnt);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void test() {
        for (int i = 0; i < 10000; i++) {
            addSheet();
        }
    }
}

打印record信息的方法

java 复制代码
    public void printlnRecords() {
        try {
            File file = new File(path);
            FileInputStream in = new FileInputStream(file);
            HSSFWorkbook workbook = new HSSFWorkbook(in);
            in.close();

            InternalWorkbook internalWorkbook = workbook.getInternalWorkbook();
            List<Record> records = internalWorkbook.getRecords();
            System.out.println("records size:" + records.size());
            int maxIndex = 0;
            int maxRecordSize = 0;
            for (int i = 0; i < records.size(); i++) {
                Record record = records.get(i);
                int recordSize = record.getRecordSize();

                System.out.println("第" + i + "个record的size:" + recordSize);
                System.out.println(record);
                System.out.println();

                if (recordSize > maxRecordSize) {
                    maxRecordSize = recordSize;
                    maxIndex = i;
                }
            }
            System.out.println("第" + maxIndex + "个record的有最大size:" + maxRecordSize);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
相关推荐
大佬,救命!!!15 小时前
etp中未运行用例顺序的定位及补齐脚本自动化生成
python·学习笔记·excel·自动化脚本·用例整理清洗
专职15 小时前
cursor中与vim插件冲突时的配置
编辑器·vim·excel
木易:_/18 小时前
【001】EXCEL办公技巧:隔行提取_excel
excel
木易:_/18 小时前
【002】EXCEL办公技巧:替换文本“=”快速提取_excel
excel
Java面试题总结18 小时前
Python 入门(四)- Openpyxl 操作 Excel 教程
开发语言·python·excel
chatexcel19 小时前
ChatExcel AI工具测试报告:从 AI Excel、数据分析到 AI PPT 的完整闭环
人工智能·数据分析·excel
babe小鑫19 小时前
想学Excel函数,学数据分析的价值分析
数据挖掘·数据分析·excel
架构源启20 小时前
深度解析:Spring Boot + Apache OpenNLP 构建企业级 NLU 系统
spring boot·后端·apache
SeaTunnel21 小时前
深度解析 Apache SeaTunnel 核心引擎三大技术创新:高可靠异步持久化与 CDC 架构优化实战
大数据·数据库·架构·apache·seatunnel
DolphinScheduler社区1 天前
第 8 篇|Apache DolphinScheduler 与 Flink Spark 数据引擎的边界、协同与最佳实践
大数据·flink·spark·开源·apache·海豚调度·大数据工作流调度