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

news2024/12/26 22:37:20

在这里插入图片描述

🔓为什么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):
 }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

产品入门第二讲:Axure产品元件库的使用

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Axure》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是…

python下使用Open3D

1.切记不要安装最新的python否则无法使用open3D &#xff0c;官网显示只支持python3.8-3.11 这是我安装的python版本 2.由于访问github很慢&#xff0c;所以我手动下载ply文件 https://github.com/isl-org/open3d_downloads/releases/download/20220201-data/fragment.ply 3…

手写进度条,鼠标移入显示悬浮框

效果 <template><div class"box"><div class"mid-box"><div class"mid-contant"><!-- 提示框 --><divv-if"hover"class"tooltip":style"{top: hovertop,}"><div>{{ ho…

c语言堆排序(详解)

堆排序 堆排序是一种基于二叉堆数据结构的排序算法&#xff0c;它的基本概念包括&#xff1a; 建立堆&#xff1a;将待排序的列表构建成一个二叉堆&#xff0c;即满足堆的性质的完全二叉树&#xff0c;可以是最大堆或最小堆。最大堆要求父节点的值大于等于其子节点的值&#x…

Linux(21):软件安装 RPM,SRPM 与 YUM

软件管理员简介 以原始码的方式来安装软件&#xff0c;是利用厂商释出的Tarball来进行软件的安装。 不过&#xff0c;你每次安装软件都需要侦测操作系统与环境、设定编译参数、实际的编译、最后还要依据个人喜好的方式来安装软件到定位。这过程是真的很麻烦的。 如果厂商先在他…

FastAPI之表单数据

FastAPI 表单数据处理教程 FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;它用 Python 3.6类型提示的特性旨在方便和快速地设计和构建 APIs&#xff0c;并且减少代码的冗余与错误。下面将介绍如何在 FastAPI 中处理…

工业级路由器在风力发电场的远程监控技术

工业级路由器在风力发电场的远程监控技术方面具有重要的应用意义。风力发电场通常由分布在广阔地区的风力发电机组组成&#xff0c;需要进行实时监测、数据采集和远程管理。工业级路由器作为网络通信设备&#xff0c;能够提供稳定可靠的网络连接和多种远程管理功能&#xff0c;…

鸿蒙OS应用开发之登录界面

在前面学习了输入文本组件和按钮组件,可以使用这两种组件来实现一些常用的功能,比如登录界面,这种界面是每个程序员经常会到遇到的,比如让用户输入用户名称和密码。 在这里我们就来实现如下面的界面: 在上面界面里,第一个文本框用来输入用户名称,第二个用来输入用户密码…

python列表的循环遍历

数据容器&#xff1a;一个可以存储多个元素的Python数据类型 有哪些数据容器&#xff1a;list&#xff08;列表&#xff09;&#xff0c;tuple&#xff08;元组&#xff09;&#xff0c;str&#xff08;字符串&#xff09;&#xff0c;set&#xff08;集合&#xff09;&#x…

【STM32】ADC模数转换器

1 ADC简介 ADC&#xff08;Analog-Digital Converter&#xff09;模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁 STM32是数字电路&#xff0c;只有高低电平&#xff0c;没有几V电压的概念&#xff…

21. python __init__.py 文件的行为

重复打印行为分析 说明结论主模块主模块所在位置不会被python认为是包 说明 我在调试代码的时候&#xff0c;发现上面的print打印了两次&#xff0c;如果将图片中的 from aaa.F import Cat 改成 from F import Cat 则print只会打印一次。这是为什么呢&#xff1f; 结论 from …

华为海思、燧原、海光等齐力打破封锁,谁主AI芯片江山| 百能云芯

近期&#xff0c;美国对英伟达出口进行了限制&#xff0c;导致英伟达无法向中国大陆销售AI芯片&#xff0c;这一局势催生了中国本土IC设计企业的崛起&#xff0c;包括华为旗下的海思科技、腾讯旗下的燧原科技&#xff0c;以及海光信息和新创公司天数智芯等纷纷抢占市场。 据百能…

微信公众服务号升级订阅号

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;首先我们要知道服务号和订阅号有什么区别。服务号侧重于对用户进行服务&#xff0c;每月可推送4次&#xff0c;每次最多8篇文章&#xff0c;发送的消息直接显示在好友列表中。订阅号更侧重于信息传…

深度探索Linux操作系统 —— Linux图形原理探讨

系列文章目录 深度探索Linux操作系统 —— 编译过程分析 深度探索Linux操作系统 —— 构建工具链 深度探索Linux操作系统 —— 构建内核 深度探索Linux操作系统 —— 构建initramfs 深度探索Linux操作系统 —— 从内核空间到用户空间 深度探索Linux操作系统 —— 构建根文件系统…

基于SpringBoot+Thymeleaf+Mybatis学生信息管理系统(源码+数据库)

一、项目简介 本项目是一套基于SpringBootThymeleafMybatis学生信息管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试…

字符雨canvas

整体思路&#xff1a; 确定好字符雨的具体字符是什么&#xff0c;需要多少行多少列这里是写死的其实也可以用循环加随机的方式生成不一样的字符雨&#xff0c;行列也可以读一下宽度然后做一下出发算一下也行首先得有一张画布搞起&#xff0c;然后循环列数去绘画字符定时器循环…

SQL语句的执行顺序怎么理解?

SQL语句的执行顺序怎么理解&#xff1f; 我们常常会被SQL其书写顺序和执行顺序之间的差异所迷惑。理解这两者的区别&#xff0c;对于编写高效、可靠的SQL代码至关重要。今天&#xff0c;让我们用一些生动的例子和场景来深入探讨SQL的执行顺序。 一、书写顺序 VS 执行顺序 SQ…

数据结构和算法(全)

1.了解数据结构和算法 1.1 二分查找 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元素的搜索算法。它的基本思想是将数组分成两半&#xff0c;然后比较目标值与中间元素的大小关系&#xff0c;从而确定应该在左半部分还是右半部分继续查找。这个…

后台业务管理系统原型模板,Axure后台组件库(整套后台管理页面)

后台业务系统需要产品经理超强的逻辑思维能力和业务理解能力&#xff0c;整理了一批后台原型组件及完整的用 Axure 8 制作的后台系统页面&#xff0c;方便产品经理们快速上手制作后台原型。 包括交互元件、首页、商品、订单、库存、用户、促销、运营、内容、统计、财务、设置、…

步进电机驱动芯片TB6600HG部分翻译

有些参数没看懂。一边设计&#xff0c;一边修正。 目录 1.芯片梗概 2.引脚配置 1)引脚含义 2)内部逻辑 3.功能详解 1&#xff09;励磁模式设置 2&#xff09;功能设置 3&#xff09;初始模式 4&#xff09;100% 电流设置(电流值) 5&#xff09;OSC 6&#xff09;衰减…