【昕宝爸爸小模块】什么是POI,为什么它会导致内存溢出?

在这里插入图片描述


➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan


       欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。


       本文章CSDN首发,欢迎转载,要注明出处哦!


       先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复!


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

  • ✅ 一、什么是POI
    • ✅1.1 Excel并没看到的那么小
    • ✅1.2 POI的溢出原理
  • ✅ 二、拓展知识仓
    • ✅2.1 几种Workbook格式
    • ✅2.2 SXSSFWorkbook是什么
    • ✅2.3 SXSSFWorkbook有哪些优点和缺点


✅ 一、什么是POI


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


✅1.1 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的源码中来看了


✅1.2 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都加载到内存中,在文件比较大的时候就会导致内存溢出。


✅ 二、拓展知识仓


✅2.1 几种Workbook格式

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


SSFWorkbook

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

XSSFWorkbook

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

SXSSFWorkbook


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

✅2.2 SXSSFWorkbook是什么


SXSSFWorkbook是Apache POI库中的一个类,用于处理大型Excel文件的写入,特别是当数据量可能非常大,以至于无法全部装入内存时。它是XSSFWorkbook的一个流式(streaming)版本,主要用于生成大数据量的Excel文件(.xlsx格式)。


SXSSFWorkbook的工作原理是,它只会将最新的几行数据(这个数量是可配置的)保存在内存中。当新的行被添加到工作表时,最旧的行将被写入到磁盘上的临时文件中,并从内存中删除。这样,SXSSFWorkbook可以用有限的内存处理几乎无限的数据量。


需要注意的是,一旦数据被写入到磁盘上的临时文件中,就不能再修改这些数据。此外,由于SXSSFWorkbook使用了流式写入技术,它的写入速度可能会受到磁盘速度的影响。


总的来说,如果你的应用程序需要生成大数据量的Excel文件,并且你担心内存溢出的问题,那么SXSSFWorkbook可能是一个很好的选择。


✅2.3 SXSSFWorkbook有哪些优点和缺点


SXSSFWorkbook是Apache POI库中的一个类,用于以流方式处理Excel文件的写入,特别是针对无法全部装入内存的大数据量场景。以下是SXSSFWorkbook的主要优点和缺点:


优点

  1. 内存友好:SXSSFWorkbook使用了一种基于硬盘的临时存储方式,将数据写入临时文件,而不是将所有数据存储在内存中。这使得它可以处理非常大的数据集,而不会导致内存溢出。
  2. 高性能:由于SXSSFWorkbook使用了临时文件存储数据,它可以有效地处理大量的数据。它避免了在内存中处理大量数据所带来的性能问题。
  3. 低内存占用:相较于XSSFWorkbook,SXSSFWorkbook在处理大型数据集时,占用的内存更少。这使得它在处理大数据量时表现更好。

缺点

  1. 模板限制:SXSSFWorkbook不支持使用现有的XLSX文件作为模板,因为它是基于流式写入的,无法预先加载整个模板文件到内存中。因此,它不能使用模板打印。
  2. IO操作开销:在写磁盘过程中,SXSSFWorkbook可能会消耗较多的IO操作时间。这可能导致内存中产生很多对象,但原来的对象可能还没有完整写入磁盘中。
  3. 功能限制:相比XSSFWorkbook,SXSSFWorkbook在某些高级功能方面可能有所限制,例如复杂的样式或公式支持可能不完全相同。另外,因为它使用到了硬盘,当数据到达硬盘以后,无法完成数据的克隆或者公式计算,sheet.clone()等方法已经无法被支持。

这些优缺点可能会随着Apache POI库的更新而发生变化。在使用SXSSFWorkbook时,建议查阅最新的官方文档以获取最准确的信息

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

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

相关文章

缓存问题 | 缓存穿透,缓存击穿,缓存雪崩

缓存穿透 关键字:强调缓存和数据库都没有数据并发访问 缓存穿透是指数据库和缓存都没有的数据,每次都要经过缓存去访问数据库,大量的请求有可能导致DB宕机。 应对策略: 使用布隆过滤器(Bloom Filter)&am…

react中优化类名写法(类似与vue的动态class对象方式)

安装和引入方式 npm install classnamesimport classNames form classsnames//render 方法中,需要动态className的地方直接参照上图使用

基于 java+springboot+mybatis电影售票网站管理系统前台+后台设计和实现

基于 javaspringbootmybatis电影售票网站管理系统前台后台设计和实现 🍅 作者主页 央顺技术团队 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 文末获取源码联系方式 📝 🍅 查看下方微信号获取联系方式 承…

数学建模-------误差来源以及误差分析

绝对误差:精确值-近似值; 举个例子:从A到B,应该有73千米,但是我们近似成了70千米;从C到D,应该是1373千米,我们近似成了1370千米,如果使用绝对误差,结果都是3…

YOLOv8训练自己的数据集,通过LabelImg

记录下labelImg标注数据到YOLOv8训练的过程,其中容易遇到labelImg的坑 数据集处理 首先在mydata下创建4个文件夹 images文件夹下存放着所有的图片,包括训练集和测试集等。后续会根据代码进行划分。 json文件夹里存放的是labelImg标注的所有数据。需要注意的是&…

【王道数据结构】【chapter2线性表】【P43t15】

单链表有环&#xff0c;是指单链表的最后一个节点的指针指向了链表中的某个结点&#xff08;通常单链表的最后一个节点的指针域是空的&#xff09;。试编写算法判断单链表是否存在环。 #include <iostream>typedef struct node{int data;node* next; }node,*list;list I…

java web 职位推荐系系统Myeclipse开发mysql数据库协同过滤算法java编程计算机网页项目

一、源码特点 java Web职位推荐系统是一套完善的java web信息管理系统 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

AWTK 开源串口屏开发(8) - 系统设置

AWTK 开源串口屏开发 - 系统设置 系统设置只是一个普通应用程序&#xff0c;不过它会用 默认模型 中一些内置的属性和命令&#xff0c;所以这里专门来介绍一下。 1. 功能 在这个例子会用到 默认模型 中一些下列内置的属性和命令&#xff1a; 内置属性 属性类型说明rtc_yea…

基于深度学习的狗狗类别检测

探索狗狗识别技术 引言1. 数据集介绍1.1 语境1.2 内容1.3 致谢 2. 项目背景与意义3. 项目实现流程3.1 数据处理与准备3.2 环境准备与工具安装3.3 模型配置与训练3.4 模型评估与预测3.5 模型推理与部署 4. 总结 服务 引言 随着人工智能技术的不断发展&#xff0c;图像识别已成为…

详解矩阵的LDU分解

目录 一. 矩阵分解 二. 解方程 三. 例题说明 四. 矩阵的LDU分解 五. 矩阵三角分解的唯一性 一. 矩阵分解 其实我们可以把一个线性系统&#xff08;Linear System&#xff09;看成两个三角系统&#xff08;Triangular Systems&#xff09;&#xff0c;本文章将解释为什么可…

Ubuntu 22.04 apt 安装 ros1 ros Noetic Ninjemys

众所周知 ros2还有很多功能没有移植&#xff0c;而ros1官方不再支持 ubuntu 20.04 之后的版本。另一方面Ubuntu 22.04 更新了很多对新硬件的驱动&#xff0c;有更好的兼容性和体验&#xff0c;这就变的很纠结。 如果想在 22.04 使用最新版本的 ros noetic 只有自己编译一个办法…

2024不可不会的StableDiffusion(二)

1. 引言 这是我关于StableDiffusion学习系列的第二篇文章&#xff0c;如果第一篇你还没有阅读&#xff0c;强烈推荐大家翻看前篇内容。在本文中&#xff0c;我们将学习构成StableDiffusion的各个基础组件&#xff0c;并针对每个组件的功能进行阐述。 闲话少说&#xff0c;我们…

JavaEE 网络编程

JavaEE 网络编程 文章目录 JavaEE 网络编程引子1. 网络编程-相关概念1.1 基本概念1.2 发送端和接收端1.3 请求和响应1.4 客户端和服务端 2. Socket 套接字2.1 数据包套接字通信模型2.2 流套接字通信模型2.3 Socket编程注意事项 3. UDP数据报套接字编程3.1 DatagramSocket3.2 Da…

matplotlib多个子图共用一个colorbar

文章目录 colorbar共用colorbar布局colorbar colorbar matplotlib默认提供的功能是&#xff0c;在多个子图中分别生成colorbar&#xff0c;例如 import numpy as np import matplotlib.pyplot as pltfig plt.figure() for i in range(2):ax fig.add_subplot(2,1,i1)ax plt…

掌握HTTP协议:GET和POST请求之间的关键差异

掌握HTTP协议&#xff1a;GET和POST请求之间的关键差异 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是用于在Web浏览器和服务器之间传递信息的协议。在HTTP中&#xff0c;GET请求和POST请求是两种最基本的请求方法。HTTP的底层是TCP/IP&#xff0c;所以GET和POST…

数据库设计的一些原则

文章目录 数据库设计原则表之间的关系一对一关系&#xff08;了解&#xff09;一对多&#xff08;多对一&#xff09;多对多联合主键和复合主键 数据库设计准则-范式1、函数依赖2、完全函数依赖3、部分函数依赖4、传递函数依赖5、码 第一范式第二范式第三范式第三范式 数据库设…

Go 从标准输入读取数据

fmt.Scan系列 fmt.Scan函数定义如下&#xff1a; // Scan scans text read from standard input, storing successive space-separated values into successive arguments. // Newlines count as space. // It returns the number of items successfully scanned. // If tha…

JZ15 二进制中1的个数(牛客)(C语言)

个人博客主页&#xff1a;https://blog.csdn.net/2301_79293429?typeblog 专栏&#xff1a;https://blog.csdn.net/2301_79293429/category_12545690.html 该题我为笨办法,与题解不同,如有疑问和见解,欢迎大家在评论区提出 题目链接: 二进制中1的个数_牛客题霸_牛客网 (now…

XSS靶场练习(pikachu和dvwa)

Pikachu靶场xss练习 反射型xss(get) 输入123发现被直接插入到了html中&#xff0c;而且输入框有字符长度限制 在url中构造payload:<script>alert(123)</script> 反射型xss(post) 查看源码发现登录界面没有任何机会&#xff1b;登录后输入123发现和xss(get)写入位…

Linux 驱动开发基础知识—— LED 驱动程序框架(四)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;V…