【昕宝爸爸小模块】深入浅出之为什么POI的SXSSFWorkbook占用内存更小

在这里插入图片描述


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


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


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


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


🔓为什么POI的SXSSFWorkbook占用内存更小?

  • 🏆POI的SXSSFWorkbook
  • 🏆POI的SXSSFWorkbook占用内存
  • 🏆扩展
    • 配置行缓存限制

🏆POI的SXSSFWorkbook

SXSSFWorkbook类是Apache POI库的一部分,它是一个流行的Java库,用于读写Microsoft Office文件。

SXSSFWorkbook类代表XSSFWorkbook类的流版本,用于创建和操作Excel(.xlsx)文件。

通过使用SXSSFWorkbook类,您可以处理大型Excel文件而不会遇到OutOfMemoryError,因为它将数据写入临时文件而不是全部保存在内存中。这使得处理大型数据集时非常高效。

以下是使用SXSSFWorkbook创建Excel文件的示例:


import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import org.apache.poi.xssf.usermodel.XSSFSheet;

import org.apache.poi.xssf.usermodel.XSSFRow;

import org.apache.poi.xssf.usermodel.XSSFCell;

import java.io.FileOutputStream;

public class ExcelWriter {
    public static void main(String[] args) {
        try (SXSSFWorkbook workbook = new SXSSFWorkbook(); // 创建一个SXSSFWorkbook对象
             FileOutputStream outputStream = new FileOutputStream("output.xlsx")) { // 创建一个文件输出流
        
            XSSFSheet sheet = workbook.createSheet("Sheet1"); // 创建一个名为"Sheet1"的工作表

            // 创建行和单元格
            for (int rowNum = 0; rowNum < 10; rowNum++) {
                XSSFRow row = sheet.createRow(rowNum); // 创建一行
                for (int cellNum = 0; cellNum < 5; cellNum++) {
                    XSSFCell cell = row.createCell(cellNum); // 创建一个单元格
                    cell.setCellValue("Row " + rowNum + ", Cell " + cellNum); // 设置单元格的值
                }
            }

            workbook.write(outputStream); // 将工作簿写入文件
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

在这个示例中,我们创建了一个新的SXSSFWorkbook,然后在其中创建了一个sheet,并将sheet填充了行和单元格。最后,我们使用FileOutputStream将工作簿写入输出文件中。

🏆POI的SXSSFWorkbook占用内存

SXSSFWorkbook 类是为了处理大型 Excel 文件而设计的。它的实现原理是通过将部分数据写入磁盘上的临时文件来减少内存占用

在SXSSFWorkbook类中,有一个类叫做sheetDataWriter,这个类的作用就是将部分数据写入磁盘上的临时文件的

public class SXSSFWorkbook implements Workbook {

    protected SheetDatalriter createSheetDatawriter() throws IOException {
    
        if( compressTmpFiles) {
        
			return new GZIPSheetDatawriter( sharedStringSource);
  		}
  		return new SheetDatawriter( sharedStringSource);
    }
}

写入过程是在 SheetDataWriter 的 writeRow 方法中实现的。此方法会被 SXSSFSheet 调用,以将行数据转换成XML 并写入临时文件。

public void writeRow(int rownum,SXSSFRow row) throws IOException {
	if ( numberOfFlushedRows == 0) 
	    _lowestIndex0fFlushedRows = rownum;
	_numberLastFlushedRow = Math.max(rownum, numberLastFlushedRow);
	_numberOfCellsOfLastFlushedRow = row.getLastCellNum();
	_numberOfFlushedRows++;
	beginRow(rownum, row);
	Iterator<Cel1> cells = row.allCellsIterator();
	int columnIndex = 0;
	while (cells.hasNext()) {
	    writeCell(columnIndex++, cells.next());
	}
	endRow();
}

writeRow()方法会循环调用writeCell()方法:

 public void writeCell(int columnIndex,Cell cell) throws IOException {
     if (cell == null) {
         return;
     }
     String ref = new CellReference( rownum, columnIndex).formatAsString();
     _out.write("<c");
     writeAttribute("r", ref);
     Cellstyle cellstyle = cell.getCellstyle();
     if (cellstyle.getIndex() != ) {
     	// need to convert the short to unsigned short as the indexes can be up to 64k
     	// ideally we would use int for this index, but that would need changes to some more
     	//APIs
     	writeAttribute("s"Integer.toString(cellStyle.getIndex() & 0xffff));
     }
     CellType cellType = cel1.getCellType();
     switch (cellType) {
     	case BLANK: {
     		_out.write('>');
     		break;
     	}
     	case FORMULA: {
     		switch(cell.getCachedFormulaResultType()) {
     			case NUMERIC:
     				writeAttribute("t","n");
     				break;
     			case STRING:
					writeAttribute("t"STCellType.STR.toString());
					break;
				case BOOLEAN:
					writeAttribute("t""b");
					break;
				case ERROR:
					writeAttribute("t""e");
					break;
     		}
     		_out.write("><f>");
     		outputQuotedString(cell.getCellFormula());
     		_out.write("</f>"):
     		switch (cell.getCachedFormulaResultType()) {
     		    case NUMERIC:
     		    double nval = cell.getNumericCellValue();
     		    	if (!Double.isNaN(nval)) {
     		    		_out.write("<v>");
     		    		_out.write(Double.tostring(nval));
     		    		_out.write("</v>");
     		    	}
     		    	break;
     		    case STRING:
     		    	String value = cell.getstringCellValue();
     		    	if(value != null && !value.isEmpty()) {
     		    		_out.write("<v>");
     		    		_out.write(value);
     		    		 _out.write("</v>");
     		    	}
     		    	break;
     		    case BOOLEAN:
     		        _out.write("><v>");
     		        _out.write(cell.getBooleanCellValue() ?1:"0");
     		        _out.write("</v>");
     		        break;
     		        case ERROR: {
     		        	FormulaError error = FormulaError.forInt(cell.getErrorCellValue());

						_out.write("><v>");
						_out.write(error.getString());
						_out.write("</v>");
						break;
     		        }
     		}
     		break;
     	}
     	case STRING:  {
     		if ( sharedStringSource != null) {
     			XSSFRichTextString rt = new XSSFRichTextString(cell.getStringCellValue());

				int sRef = sharedStringSource.addSharedStringItem(rt);

				
     			writeAttribute("t"STCellType.s.toString());

				_out.write("><v>");
				_out.write(String.value0f(sRef));
				_out.write("</v>");
     		} else {
     		    writeAttribute("t","inlineStr");
     		    _out.write("><is><t");
     		    if (hasLeadingTrailingSpaces(cell.getStringCellValue())) {
     		        writeAttribute("xml:space","preserve");
     		    }
     		    out .write(">");
     		    outputQuotedstring(cell.getstringCellValue());
     		    _out.write("</t></is>");
     		}
     		break;
     	}
     	case NUMERIC: {
     		writeAttribute("t""n");
     		_out.write("><v>");
     		_out.write(Double.toString(cell.getNumericCellValue()));
     		_out .write("</v>) ;
     		break;
     	}
     	case BOOLEAN: {
     		writeAttribute("t""b");
     		_out .write("><v>) ;
     		_out.write(cell.getBooleanCellValue() ?"1” :"0");
     		out.write("</v>");
     		break;
     	}
     	case ERROR: {
     		FormulaError error = FormulaError.forInt(cell.getErrorCellValue());


			writeAttribute("t","e");
			_out .write("><v>);
			_out.write(error.getstring());
			_out.write("</v>");
			break;
     	}
     	default: {
     		throw new IllegalStateException("Invalid cell type: " + cellType);
     	}
     }
     _out.write("</c>");
 }

在这个方法中,数据会在 out.write(…) 调用时写入磁盘,这里的_out其实就是一个写入磁盘文件的Writer,他的write方法就会把内容写入到临时文件中。

我尝试着在 out初始化的地方,也就是:

public SheetDatawriter() throws IOException {
	_fd = createTempFile();
	_out = createWriter( fd);
}

中加了断点,就能在运行过程中找到这个临时文件,tail一下临时文件就会发现它不断地有文件写入。

在这里插入图片描述
感兴趣的也可以debug看一下这个临时文件的内容,其实它就是一个xml文件,然后写入的就是我们excel中的内容。

在这里插入图片描述
所以,在SXSSFWorkbook中,我们在写入文件时,并不是把所有内容都暂留在内存内,而是会把部分数据写入临时文件,来减少对内存的占用,内存中只保留当前的一部分数据,这样就可以避免内存溢出的问题了。

🏆扩展

配置行缓存限制

我们可以主动设置行缓存限制,超过这个限制的数据将被写入磁盘上的临时文件。在创建SXSSFWorkbook的时候,可以指定rowAccessWindowSize来实现。

/**
 * Construct an empty workbook and specify the window for row access.
 * <p>
 * When a new node is created via (@link SXSSFSheet#createRow) and the total number
 * of unflushed records would exceed the specified value, then the
 * row with the lowest index value is flushed and cannot be accessed
 *  via f@link SXSSFSheet#getRow] anymore.
 * </p>
 * <p>
 * A value of <code>-1</code> indicates unlimited access. In this case all
 * records that have not been flushed by a call to <code>flush()</code> are available
 * for random access.
 * </p>
 * <p>
 * A value of <code>0</code> is not allowed because it would flush any newly created row
 * without having a chance to specify any cells.
 * </p>
 * @param rowAccesslindowSize the number of rows that are kept in memory until flushed out , see above.
 */
 public SXSSFWorkbook(int rowAccesswindowSize){
 	this(null /*workbook*/, rowAccessWindowSize):
 }

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

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

相关文章

C++ -- 入门(引用)

1.引用 1.1引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如&#xff1a;李逵&#xff0c;在家称为"铁牛"&#xff0c;江湖上人称&q…

搭建Android开发环境—— 熟悉Android开发工具,掌握Android移动端开发环境的搭建、项目导入,并能够将项目部署到模拟器和真机进行测试。

搭建Android开发环境 一、实验目的 熟悉Android开发工具&#xff0c;掌握Android移动端开发环境的搭建、项目导入&#xff0c;并能够将项目部署到模拟器和真机进行测试。 二、实验设备及器件 1、JDK1.8安装包 2、Android Studio安装包 三、实验内容 完成JDK和Android Stud…

java web mvc-06-play framework intro

拓展阅读 Spring Web MVC-00-重学 mvc mvc-01-Model-View-Controller 概览 web mvc-03-JFinal web mvc-04-Apache Wicket web mvc-05-JSF JavaServer Faces web mvc-06-play framework intro web mvc-07-Vaadin web mvc-08-Grails 开源 The jdbc pool for java.(java …

中仕教育:“三不限”事业编的含义

所谓“三不限”&#xff0c;是指在报考事业单位时&#xff0c;对考生的户籍、年龄、学历不作任何限制。所以全国各地的考生只要符合招聘条件&#xff0c;都可以报考。所以每一年的三不限岗位竞争压力都比较大&#xff0c;报考人数都有很多。 ‘三不限’岗位招考信息在哪里看?…

测试用例评审流程

1:评审的过程 A:开始前做好如下准备 1、确定需要评审的原因 2、确定进行评审的时机 3、确定参与评审人员 4、明确评审的内容 5、确定评审结束标准 6、提前至少一天将需要评审的内容以邮件的形式发送给评审会议相关人员。并注明详审时间、地点及偿参与人员等。 7、 在邮件中提醒…

智慧之光:ChatGPT 引领工作效率新纪元

随着科技的不断发展&#xff0c;人工智能&#xff08;AI&#xff09;已经逐渐融入我们的日常生活和工作中。其中&#xff0c;ChatGPT 作为一种先进的 AI 技术&#xff0c;正逐步改变我们的工作方式&#xff0c;提升我们的工作效率。本文灸哥将介绍如何利用ChatGPT提升工作效率&…

数据结构(C语言版)代码实现(三)——单链表部分代码实现

目录 格式 头文件 宏定义 线性表的单链表存储结构 按位查找 插入元素 删除元素 头插法建立单链表 合并非递减单链表 其他基本操作 完整版 测试代码&#xff08;主函数&#xff09; 测试结果 格式 参考 2.3节 线性表的链式表示和实现 头文件 宏定义 #pragma onc…

基于机会网络编码(COPE)的卫星网络路由算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1机会网络编码&#xff08;COPE&#xff09;概述 4.2COPE算法原理 4.2.1 编码机会预测 4.2.2 编码决策 4.2.3 数据包编码 4.2.4 数据包传输 4.2.5 数据包解码 5.完整程序 1.程序功能…

从零学Java MySQL

MySQL 文章目录 MySQL初识数据库思考&#xff1a;1 什么是数据库&#xff1f;2 数据库管理系统 初识MySQLMySQL卸载MySQL安装1 配置环境变量2 MySQL目录结构及配置文件 连接MySQL数据库基本命令MySQL基本语法&#xff1a;1 查看MySQL服务器中所有数据库2 创建数据库3 查看数据库…

12.前端--CSS-背景属性

1.背景颜色 样式名称&#xff1a; background-color 定义元素的背景颜色 使用方式: background-color:颜色值; 其他说明&#xff1a; 元素背景颜色默认值是 transparent&#xff08;透明&#xff09;      background-color:transparent; 代码演示&#xff1a; 背景色…

【裁员潮】技术变革下的职业危机,程序员会有多大影响,又应该如何面对

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《技术变革下的裁员潮》 文章将以博主的角度进行讲述&#xff0c;理解和水平有限&#xff0c;不足之处&#xff0c;望指正。 目录 背景硬实力职业危机…

推荐收藏!48道数据分析师高频面试题汇总!

大家好&#xff0c;最近很多小伙伴私信我&#xff0c;讲一下数据分析的面试题&#xff0c;今天给大家整理了48道数据分析师面试时被频繁问到的题目&#xff0c;找数据分析岗位的同学一定要码住认真看。 想了解最新的面试动态、最新高频考点、技术交流的同学&#xff0c;可以文…

notepad++ v8.5.3 安装插件,安装失败怎么处理?下载进度为0怎么处理?

notepad v8.5.3 安装插件&#xff0c;安装失败&#xff1f;下载进度为0&#xff0c;怎么处理&#xff1f; 安装 进度 进度条没有进度 &#xff0c;然后就退出了&#xff0c;自动打开程序&#xff0c;不知道什么问题&#xff0c;插件管理下面也没有插件显示 找到问题了&#x…

C++ 数论相关题目(欧拉函数)

欧拉函数 给定 n 个正整数 ai &#xff0c;请你求出每个数的欧拉函数。 欧拉函数的定义 1∼N 中与 N 互质的数的个数被称为欧拉函数&#xff0c;记为 ϕ(N) 。 若在算数基本定理中&#xff0c;Npa11pa22…pamm &#xff0c;则&#xff1a; ϕ(N) Np1−1p1p2−1p2…pm−1pm 输…

BGP路由反射-数据中心IDC项目经验

一、背景描述 R1,R2,R3在AS200区域内&#xff0c;R1和R2,R1和R3建立OSPF&#xff0c;宣告接口互联. AS200区域内&#xff0c;R1和R2建立IBGP, R1和R3建立IBGP R2和R4建立EBGP, R3和R5建立EBGP。 网络拓扑&#xff1a; 二、故障现象 R1和R2可以收到来自AS100区域R4的E…

技术驱动宠物健康:宠物在线问诊系统的高效搭建手册

在数字化时代&#xff0c;技术正在催生出许多创新的医疗服务&#xff0c;而宠物在线问诊系统便是其中一项引领潮流的创举。本文将为你提供一份高效搭建宠物在线问诊系统的手册&#xff0c;通过技术代码示例&#xff0c;让你轻松打造一套技术驱动的宠物健康管理系统。 1. 架构…

CSS 楼梯弹弹球

<template><view class="loader"></view> </template><script></script><style>body {background-color: #212121;/* 设置背景颜色为 #212121 */}.loader {position: relative;/* 设置定位为相对定位 */width: 120px;/* 设…

Linux之快速入门

一、Linux目录结构 从Windows转到Linux最不习惯的是什么&#xff1a; 目录结构 Windows会分盘&#xff0c;想怎么放东西就怎么放东西&#xff0c;好处自由&#xff0c;缺点容易乱 Linux有自己的目录结构&#xff0c;不能随随便便放东西 /&#xff1a;根目录/bin:二进制文件&…

【学术论文写作】 鲁棒性实验写作的行文逻辑

文章目录 一、声明二、行文思路三、示例范文一范文二 一、声明 自己总结的&#xff0c;有问题望指正&#xff01; 二、行文思路 为什么要做鲁棒性测试怎么做实验结论对结果的解释 三、示例 PPT 范文一 2022, TIM, “A Robust and Reliable Point Cloud Recognition Netw…

【C++干货铺】C++中的四种类型转换

个人主页点击直达&#xff1a;小白不是程序员 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 C语言中的类型转换 为什么C需要四种类型转化 C强制类型转换 static_cast reinterpret_cast const_cast dynamic_cast RTTI C语言中的类型转换 在C语言中&…