【什么是POI,为什么它会导致内存溢出?】

什么是POI,为什么它会导致内存溢出

  • 什么是POI
    • Excel并没看到的那么小
    • POI的溢出原理
  • 拓展知识
    • 几种Workbook格式

什么是POI

Apache POl,是一个非常流行的文档处理工具,通常大家会选择用它来处理Excel文件。但是在实际使用的时候经常会遇到内存溢出的情况,那么,为啥他会导致内存溢出呢?

Excel并没看到的那么小

我们通常见到的xlsx文件,其实是一个个压缩文件。它们把若千个XML格式的纯文本文件压缩在一起,Excel就是读取这些压缩文件的信息,最后展现出一个完全图形化的电子表格。

所以,如果我们把xlsx文件的后缀更改为.zip或 .rar,再进行解压缩,就能提取出构成Excel的核心源码文件。解压会发现解压后的文件中有3个文件夹和1个XML格式文件:

在这里插入图片描述
_rels 文件夹看里面数据像是一些基础的配置信息,比如 workbook 文件的位置等信息一般不会去动它。

docProps 文件夹下重要的文件是一个app.xml,这里面主要存放了 sheet 的信息,如果想添加或编辑 sheet 需要改这个文件,其他文件都是一些基础信息的数据,比如文件所有者,创建时间等。

x文件夹是最重要的一个文件夹里面存放了Sheet 中的数据,行和列的格式,单元格的格式,sheet的配置信息等等信息。

所以,实际上我们处理的xlsx文件实际上是一个经过高度压缩的文件格式,背后是有好多文件支持的。所以,我们看到的一个文件可能只有2M,但是实际上这个文件未压缩情况下可能要比这大得多。

在这里插入图片描述
也就是说,POI在处理的时候,处理的实际上并不只是我们看到的文件大小,实际上比它的大小要大好几倍。

这是为什么明明我们处理的文件只有100多兆,但是实际却可能占用1G内存的其中一个原因。当然这只是其中一个原因,还有一个原因,我们就需要深入到POI的源码中来看了

POI的溢出原理

我们拿POI的文件读取来举例,一般来说文件读取出现内存溢出的情况更多一些。以下是一个POI文件导出的代码示例:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class ExcelReadTest {
    public static void main(String[] args) {
        //指定要读取的文件路径
        String filename = "example.xlsx";
        try (FileInputStream fileInputStream = new FileInputStream(new File(filename))) {
            //创建工作簿对象
            Workbook workbook = new XSSFWorkbook(fileInputStream);
            
            // 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);
            
            //遍历所有行
            for (Row row : sheet) {
                // 遍历所有单元格
                for (Cell cell : row) {
                    Thread.sleep(100); //添加注释:暂停程序执行100毫秒
                    
                    // 根据不同数据类型处理数据
                    switch (cell.getCellType()) {
                        case STRING:
                            System.out.print(cell.getStringCellValue() + "\t"); //添加注释:输出单元格的字符串值
                            break;
                        case NUMERIC:
                            if (DateUtil.isCellDateFormatted(cell)) {
                                System.out.print(cell.getDateCellValue() + " t"); //添加注释:输出单元格的日期值
                            } else {
                                System.out.print(cell.getNumericCellValue() + " t"); //添加注释:输出单元格的数值
                            }
                            break;
                        case BOOLEAN:
                            System.out.print(cell.getBooleanCellValue() + " t"); //添加注释:输出单元格的布尔值
                            break;
                        case FORMULA:
                            System.out.print(cell.getCellFormula() +"t"); //添加注释:输出单元格的公式
                            break;
                        default:
                            System.out.print(""); //添加注释:不做任何操作
                    }
                }
                System.out.println(); //添加注释:换行
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

这里面用到了一个关键的XSSFWorkbook类,

public XSSFWorkbook(InputStream is) throws IOException {
	
	this(PackageHelper.open(is);
}
public static OPCPackage open(InputStream is) throws IOException {

	
	
	try {
		
		return OPCPackage.open(is);
		
	}catch (InvalidFormatException e) {
		
		throw new POIXMLException(e);
		
	}
}

最终会调用到OPCPackage.open方法,看看这个方法是怎么实现的:

/**
 *  Open a package.
 *
 * 
 * Note - uses quite a bit more memory than (@link #open(String)}, which
 * doesn't need to hold the whole zip file in memory, and can take advantage
 * of native methods
 * 
 *aparam in
 *
 *           The InputStream to read the package from
 *           
 * @return A PackageBase object
 * 
 * 
 * @throws InvalidFormatException
 * 
 *               Throws if the specified file exist and is not valid. 
 *               
* @throws IOException If reading the stream fails
*/

public static OPCPackage open(InputStream in) throws InvalidFormatException,IOException {
    OPCPackage pack = new ZipPackage(in,PackageAccess.READ_WRITE);
    try {
    	
  
    	if (pack.partList == nul1) {
    		(pack.getParts();
    	}
    	
    }catch (InvalidFormatException  RuntimeException e) {
    	

    	IOUtils.close0uietly(pack);
    	
    	throw e;
    }
return pack;
}

这行代码的注释中说了:这个方法会把整个压缩文件都加载到内存中。也就是把整个 Excel 文档加载到内存中,可想而知,这在处理大型文件时是肯定会导致导致内存溢出的。

也就是说我们使用的XSSFWorkbook (包括HSSFWorkbook也同理) 在外理Excel的过程中会将整个Excel都加载到内存中,在文件比较大的时候就会导致内存溢出。

拓展知识

几种Workbook格式

POI中提供了很多种Workbook API来操作Excel,有的适合大文件读写,有的不适合。

SSFWorkbook

  • 用于处理Excel的.xsl格式(即Excel 97-2003)。

XSSFWorkbook

  • 用于处理 Excel 的.xlsx 格式(即 Excel 2007 及以后版本的)支持更大的数据集和更多的功能,如更好的样式和公式支持。但是相对于HSSFWorkbook,它在处理大数据集时可能占用更多内存。

SXSSFWorkbook

  • 用于处理xlsx 格式。它是 XSSFWorkbook 的流式版本,专门设计用于处理大数据集。通过将数据写入临时文件而非全部保留在内存中,显著减少内存消耗。特别适合用于创建大型数据集的 Excel 文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/243156.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关键点检测☞png格式换bmp,且labelme标注的json中imagePath同步修改格式

import os import cv2 import jsondef bmp2jpg(in_img_path, out_dir_name): # .png -> .bmp# img = cv2.imread(in_img_path) # 彩色图片,位深24img =</

【虹科分享】基于Redis Enterprise,LangChain,OpenAI 构建一个电子商务聊天机器人

如何构建你自己的商务聊天机器人&#xff1f;注意哦&#xff0c;是你自己的聊天机器人。一起来看看Redis Enterprise的向量检索是怎么帮你实现这个愿望的吧。 鉴于最近人工智能支持的API和网络开发工具的激增&#xff0c;似乎每个人都在将聊天机器人集成到他们的应用程序中。 …

使用入耳耳机对耳朵有损害吗?入耳耳机和骨传导耳机哪款更值得入手?

由于入耳式耳机的传声原理&#xff0c;长时间使用是会对耳朵造成损害的&#xff0c;骨传导耳机相比与入耳耳机&#xff0c;不用入耳佩戴&#xff0c;还能在一定程度上保护听力&#xff0c;所以骨传导耳机更值得入手。 一、入耳耳机和骨传导耳机有什么不同 人的听觉系统分为搜…

c 语言 堆的解析(自我理解)!!!堆排序,建堆

目录 1.堆是什么&#xff1f; 2.堆的实现和接口。&#xff08;小堆&#xff09; 1.头文件 2.初始化 3.摧毁 4.向上调整&#xff08;重点&#xff09; 5.向下调整&#xff08;重点&#xff09; 6.插入&#xff08;重点&#xff09; 7.删除&#xff08;重点&#xff09; …

【Linux】:线程(三)同步和消费者模型

线程的同步 一.条件变量二.生产者和消费者模型1.概念和特点2.实现基于阻塞队列的生产者消费者模型 同步&#xff1a;在保证数据安全的前提下&#xff0c;让线程能够按照某种特定的顺序访问临界资源&#xff0c;从而有效避免饥饿问题&#xff0c;叫做同步。 竞态条件&#xff1a…

【map】【动态规划】LeetCode2713:矩阵中严格递增的单元格数

本文涉及的基础知识点 二分查找算法合集 题目 给你一个下标从 1 开始、大小为 m x n 的整数矩阵 mat&#xff0c;你可以选择任一单元格作为 起始单元格 。 从起始单元格出发&#xff0c;你可以移动到 同一行或同一列 中的任何其他单元格&#xff0c;但前提是目标单元格的值 …

群晖(Synology)更换硬盘时间和精神双重折磨的教训

话说玩磁盘阵列的最后结果就是时间上负担不起&#xff0c;并且还被嫌弃。 在磁盘都到位后下一步就是要选择冗余类型了&#xff0c;对大部分人来说使用群晖自己提供的就好了&#xff0c;通常是 SHR。 什么是 SHR Synology Hybrid RAID&#xff08;SHR&#xff09;是 Synology…

为什么要使用国际语音群呼系统?

1.降本增效 通过批量导入客户的电话号码&#xff0c;由系统自动完成批量呼叫&#xff0c;企业可以节省人工拨号的费用&#xff0c;高效助力企业业务增长&#xff1b; 2.降低流失 通过批量群呼&#xff0c;企业可以724小时高并发无故障运行&#xff0c;智能锁定意向客户&…

【c语言】【visual studio】动态内存管理,malloc,calloc,realloc详解。

引言&#xff1a;随着大一期末的到来&#xff0c;想必许多学生都学到内存的动态管理这一部分了&#xff0c;看望这篇博客后&#xff0c;希望能解除你心中对这一章节的疑惑。 (・∀・(・∀・(・∀・*) 1.malloc详解 malloc的头文件是#include <sdtlib.h>,malloc - C Ref…

bugku--文件包含

点击 访问一下index.php 页面报错 既然是文件包含就可以想到php伪协议 这里我们需要访问本地文件系统 构造我们的payload ?filephp://filter/readconvert.base64-encode/resourceindex.php base64解码 得到我们的flag 提交就好啦 ?filephp://filter/readconvert.base64-e…

bugku--source

dirsearch扫一下 题目提示源代码&#xff08;source&#xff09; 也就是源代码泄露&#xff0c;然后发现有.git 猜到是git泄露 拼接后发现有文件 但是点开啥也没有 kali里面下载下来 wegt -r 下载网站的所有内容 ls 查看目录 cd 进入到目录里面 gie reflog 引用日志使用…

过滤(删除)迭代对象中满足指定条件的元素itertools.filterfalse()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 过滤(删除)迭代对象中 满足指定条件的元素 itertools.filterfalse() [太阳]选择题 请问以下代码输出的结果是&#xff1f; a [1, 2, 3, 4, 5] print("【显示】a ",a) import ite…

【SpringBoot】FreeMarker视图渲染

目录 一、FreeMarker 简介 1.1 什么是FreeMarker&#xff1f; 1.2 Freemarker模板组成部分 1.3 为什么要使用FreeMarker 二、Springboot集成FreeMarker 2.1 配置 2.2 数据类型 2.2.1 字符串 2.2.2 数值 2.2.3 布尔值 2.2.4 日期 2.3 常见指令 2.3.2 assign 2.3…

C++ 重载括号运算符示例

重载括号运算符的写法是&#xff0c; 返回值 operator() ( 表达式表 ) 参数个数不限&#xff1b; VC6新建一个单文档工程&#xff1b; 添加一个示例类&#xff0c;比较短&#xff0c;直接加到视类h文件的头部&#xff1b; class A { public:// 重载 括号 () 运算符int oper…

scratch魔法变变变 2023年12月中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析

目录 scratch魔法变变变 一、题目要求 1、准备工作 2、功能实现 二、案例分析

webpack详细教程

1&#xff0c;什么是webpackwebpack | webpack中文文档 | webpack中文网 Webpack 不仅是一个模块打包器(bundler)&#xff0c;更完整的讲是一个前端自动化构建工具。在 Webpack 看来前端的所有资源文件(s/json/css/img/less/...)都会作为横块处理它将根据模块的依赖关系进行静…

进程概念【linux】

进程基础 在学习进程之前&#xff0c;首先要有一定的计算机硬件和软件基础。 硬件基础&#xff1a;冯诺依曼体系结构 如图&#xff0c;是计算机在硬件上的体系结构。 下面举出一些常见的输入输出设备&#xff08;有些设备只作输出设备&#xff0c;或者只作输入设备&#xff…

xtu oj 1328 数码和

题目描述 一个10进制数n在2∼16进制下可以得到的不同的数码和&#xff0c;求在这些数码和中出现次数最多的数码和。 比如20&#xff0c; 其中数码和2和4分别出现了3次&#xff0c;为最多出现次数。 输入 第一行是一个整数T(1≤T≤1000)&#xff0c;表示样例的个数。 以后每行…

【数据结构(十一·多路查找树)】B树、B+树、B*树(6)

文章目录 1. 二叉树 与 B树1.1. 二叉树存在的问题1.2. 多叉树 的概念1.3. B树 的基本介绍 2. 多叉树——2-3树2.1. 基本概念2.2. 实例应用2.3. 其他说明 3. B 树、B树 和 B*树3.1. B树 的介绍3.2. B树 的介绍3.2. B*树 的介绍 1. 二叉树 与 B树 1.1. 二叉树存在的问题 二叉树…

计算机视觉(P2)-计算机视觉任务和应用

一、说明 在本文中&#xff0c;我们将探讨主要的计算机视觉任务以及每个任务最流行的应用程序。 二、图像内容分类 2.1. 图像分类 图像分类是计算机视觉领域的主要任务之一[1]。在该任务中&#xff0c;经过训练的模型根据预定义的类集为图像分配特定的类。下图是著名的CIFAR…