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

在这里插入图片描述

🔓为什么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/244775.html

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

相关文章

第五节JavaScript typeof、类型转换与正则表达式

一、typeof、null和undefined 1、typeof操作符 使用typeof操作符来检测变量的数据类型。 实例&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>JavaScript基础知识学习</title></head><bod…

单元测试二(实验)-云计算2023.12-云南农业大学

1、实践系列课《深入浅出Docker应用》 https://developeraliyun.com/adc/scenarioSeries/713c370e605e4f1fa7be903b80a53556?spma2c6h.27088027.devcloud-scenarioSeriesList.13.5bb75b8aZHOM2w 容器镜像的制作实验要求 创建Dockerfile文件: FROM ubuntu:latest WORKDIR data…

C++初阶(十六)优先级队列

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、priority_queue的介绍和使用1、priority_queue的介绍2、priority_queue的使用 二、priori…

高性能国产TYPE-C/DP/EDP转MIPIDSI/CSI/LVDS,龙迅LT7911D,支持高达4K60HZ的分辨率

LT7911D概述&#xff1a; T7911D是一款高性能TYPE-C/DP/EDP转2 PORT MIPI或者LVDS的芯片&#xff0c;目前主要在AR/VR或者显示器上应用的很多&#xff0c;对于DP1.2输入&#xff0c;LT7911D可配置为1/2/4车道。自适应均衡化使其适用于长电缆应用&#xff0c;最大带宽可达21.6G…

【AntDB数据库】亚信安慧通过CMMI5级认证

近日&#xff0c;湖南亚信安慧科技有限公司&#xff08;以下简称“亚信安慧”&#xff09;通过CMMI5级认证。这标志着亚信安慧在软件研发能力、过程组织能力、项目管理能力、解决方案交付能力等方面达到了国际先进水平&#xff0c;具备为通信、金融、交通、能源、物联网等行业客…

图片如何无损放大?亲测三款好用图片无损放大工具

图片如何无损放大&#xff1f;当遇到图片不清晰或模糊受损的情况时&#xff0c;我们往往希望能够使用这张图片。然而&#xff0c;图片的模糊问题往往令人困扰。幸运的是&#xff0c;我们可以使用一些方法将图片无损放大&#xff0c;从而解决照片模糊的问题。今天&#xff0c;我…

开源云原生网关Linux Traefik本地部署结合内网穿透远程访问

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

实验01:静态路由配置实验

1.实验目的&#xff1a; 本次实验的主要目的是了解静态路由的配置和实现原理&#xff0c;熟悉路由器的基本操作&#xff0c;掌握在网络中进行静态路由配置的方法和技巧。 2.实验内容&#xff1a; 搭建网络拓扑&#xff0c;包括三台路由器和两台PC。配置路由器的IP地址和路由…

深入理解C语言的函数参数

1、一个简单的函数 int Add(int x, int y) {return x y; }int main() {printf("%d", Add(2, 3, 4, 5, 6));return 0; } 这一段足够简单的代码&#xff0c;闭眼都能知道运行结果会在屏幕上打印 5 。那编译器是怎么处理后面的 4、5、6 &#xff1f; 我们再看看这个函…

【Spring教程28】Spring框架实战:从零开始学习SpringMVC 之 请求与请求参数详解

目录 1 设置请求映射路径1.1 环境准备 1.2 问题分析1.3 设置映射路径 2 请求参数2.1 环境准备2.2 参数传递2.2.1 GET发送单个参数2.2.2 GET发送多个参数2.2.3 GET请求中文乱码2.2.4 POST发送参数2.2.5 POST请求中文乱码 欢迎大家回到《Java教程之Spring30天快速入门》&#xff…

Vue3-17-ref 模板引用的基本使用

什么是模板引用 简单来说&#xff0c;就是在 js 代码中 获取到 html 中的dom元素的完整信息&#xff0c; 从而实现直接操作dom元素的效果。模板引用的语法 1、给 dom 元素添加 ref名称 属性&#xff0c;指定一个独有的名称&#xff1b; 2、js 中 声明一个 与 dom 元素的 ref 同…

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

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

【问题解决】unable to do port forwarding: socat not found

问题复现 前阵子应公司要求做华为云平台的调研&#xff0c;写了一篇文档包含将华为云CCE下载kuberctl配置及使用kubectl转发流量到本地的操作。 今天一早上同事就发来一个错误界面&#xff0c;说是Java远程调试转发过来的端口出现问题&#xff0c;如下图&#xff1a; 处理思路…

wgcloud访问页面如何加前缀/wgcloud

nginx配置实现加/wgcloud - WGCLOUD

Linux:ELF

文章目录 前置知识从文本文件到可执行文件经历的阶段编译器gcc目标文件 ELFSection&#xff08;节&#xff09;Segment&#xff08;段&#xff09;从链接角度和从程序角度看ELF文件1. Section Header Table:2. Program Header Table: 参考 前置知识 从文本文件到可执行文件经历…

树莓派zero w入坑指南

树莓派zero w入坑指南 入坑契机 说起创客不得不提到开源硬件Raspberry Pi(树莓派)。它是一款基于ARM的微型电脑主板&#xff0c;以MicroSD卡为硬盘&#xff0c;提供HDMI和USB等外部接口&#xff0c;可连接显示器和键鼠。以上部件全部整合在一张仅比信用卡稍大的主板上&#x…

jvm阶段小节

文章目录 静态变量与局部变量的对比&#xff1a; 我们知道类变量有两次初始化的机会&#xff0c;第一次是在“准备阶段”&#xff08;链接&#xff09;&#xff0c;执行系统初始化&#xff0c;对类变量设置默认值&#xff0c;另一次则是在“初始化”阶段&#xff0c;赋予程序员…

Postman测试 restful 接口!

日常开发中经常会遇到没有前提界面&#xff0c;直接调用后台 restful 接口的情景&#xff0c;不管时后台代码先行&#xff0c;并且开发完之后开发人员进行自测还是&#xff0c;或者是专业测试进行 restful 接口测试&#xff0c;都需要一款工具&#xff0c;现在就来介绍 postman…

如何在本地搭建Oracle数据库并实现无公网ip通过PLSQL工具远程连接数据库

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 正文开始前给大家推荐个网站&#xff0c;前些天发…

PythonStudio:一款国人写的python及窗口开发编辑IDE,可以替代pyqt designer等设计器了

本款软件只有十几兆&#xff0c;功能算是强大的&#xff0c;国人写的&#xff0c;很不错的python界面IDE.顶部有下载链接。下面有网盘下载链接&#xff0c;或者从官网直接下载。 目前产品免费&#xff0c;以后估计会有收费版本。主页链接&#xff1a;PythonStudio-硅量实验室 作…