JAVA 导出报表 大数据量 sxssfworkbook的使用

sxssfworkbook

之前报表导出使用得是XSSFWorkbook 但是导出数据量过大的时候经常出现OOM,现在发现使用sxssfworkbook 减少内存压力

官网是这样介绍的:
SXSSF (package: org.apache.poi.xssf.streaming) is an API-compatible streaming extension of XSSF to be used when very large spreadsheets have to be produced, and heap space is limited. SXSSF achieves its low memory footprint by limiting access to the rows that are within a sliding window, while XSSF gives access to all rows in the document. Older rows that are no longer in the window become inaccessible, as they are written to the disk.
翻译过来就是:
SXSSF (package: org.apache.poi.xssf.streaming)是XSSF的api兼容流扩展,用于必须生成非常大的电子表格,并且堆空间有限的情况下。 SXSSF通过限制对滑动窗口内的行的访问来实现低内存占用,而XSSF允许访问文档中的所有行。 不再在窗口中的旧行在被写入磁盘时变得不可访问。

简单来说 在创建 SXSSFWorkbook 对象时,你可以设置缓存和窗口的大小。这可以通过构造方法 SXSSFWorkbook(int rowAccessWindowSize) 来完成,其中 rowAccessWindowSize 表示在内存中保持的行数。这样,当超过这个数量时,将会把数据写入磁盘。然后分批写入文件。减少内存占用

简单的Demo:

import junit.framework.Assert;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;public static void main(String[] args) throws Throwable {// 设置内存最大行数是1000行 (如果不带参数则默认是100行,也可以选择-1 就是全量输出)SXSSFWorkbook wb = new SXSSFWorkbook(100); //创建sheet页Sheet sh = wb.createSheet();for(int rownum = 0; rownum < 1000; rownum++){// 创建行Row row = sh.createRow(rownum);for(int cellnum = 0; cellnum < 10; cellnum++){//创建单元格Cell cell = row.createCell(cellnum);String address = new CellReference(cell).formatAsString();//设置单元格的值cell.setCellValue(address);}}//rownum < 900的行被刷新并且不可访问 (因为他设置了100行,所以他每一百行会从磁盘中加载到内存中,写入完成后 就会在内存中删除掉,接着会下一个一百行)for(int rownum = 0; rownum < 900; rownum++){//Assert.assertNotNull() 方法用于验证给定的对象不为空(即非 null)。如果 sh.getRow(rownum) 返回的对象为 null,将会抛出 AssertionError。Assert.assertNull(sh.getRow(rownum));}// 最后100行仍然在内存中for(int rownum = 900; rownum < 1000; rownum++){Assert.assertNotNull(sh.getRow(rownum));}//输出流FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");//写入wb.write(out);out.close();wb.dispose();}

源码分析:

构造函数:
如果是有现有得模板,需要在模板加入数据,需要先创建XSSFWorkbook 然后在放入SXSSFWorkbook


public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles) {this._sxFromXHash = new HashMap();this._xFromSxHash = new HashMap();//默认100行this._randomAccessWindowSize = 100;//这个是用来判断是否创建临时文件的this._compressTmpFiles = false;this.setRandomAccessWindowSize(rowAccessWindowSize);this.setCompressTempFiles(compressTmpFiles);if (workbook == null) {this._wb = new XSSFWorkbook();} else {this._wb = workbook;for(int i = 0; i < this._wb.getNumberOfSheets(); ++i) {XSSFSheet sheet = this._wb.getSheetAt(i);this.createAndRegisterSXSSFSheet(sheet);}}}

创建临时文件: 其实在创建Sheet页得时候就创建了这个临时文件

//创建SheetSheetDataWriter createSheetDataWriter() throws IOException {//判断 compressTmpFiles 构造函数默认是false,所以第一次默认执行 SheetDataWriterreturn (SheetDataWriter)(this._compressTmpFiles ? new GZIPSheetDataWriter() : new SheetDataWriter());}//这个地方其实就是创建临时文件
public SheetDataWriter() throws IOException {this._out = this.createWriter(this._fd);}public Writer createWriter(File fd) throws IOException {return new BufferedWriter(new FileWriter(fd));}//存储的路径:这样看其实是存在java.io.tmpdir的系统的环境变量下面
private void createPOIFilesDirectory() throws IOException {if (this.dir == null) {String tmpDir = System.getProperty("java.io.tmpdir");if (tmpDir == null) {throw new IOException("Systems temporary directory not defined - set the -Djava.io.tmpdir jvm property!");}this.dir = new File(tmpDir, "poifiles");}this.createTempDirectory(this.dir);} 

写入文件

public void write(OutputStream stream) throws IOException {Iterator i$ = this._xFromSxHash.values().iterator();while(i$.hasNext()) {SXSSFSheet sheet = (SXSSFSheet)i$.next();sheet.flushRows();}File tmplFile = File.createTempFile("poi-sxssf-template", ".xlsx");try {FileOutputStream os = new FileOutputStream(tmplFile);try {this._wb.write(os);} finally {os.close();}this.injectData(tmplFile, stream);} finally {//这个地方会删除掉临时文件tmplFile.delete();}}

创建行得时候 入临时文件

public Row createRow(int rownum) {
//这个是最大得行数 1048576 int maxrow = SpreadsheetVersion.EXCEL2007.getLastRowIndex();if (rownum >= 0 && rownum <= maxrow) {if (rownum <= this._writer.getLastFlushedRow()) {throw new IllegalArgumentException("Attempting to write a row[" + rownum + "] " + "in the range [0," + this._writer.getLastFlushedRow() + "] that is already written to disk.");} else if (this._sh.getPhysicalNumberOfRows() > 0 && rownum <= this._sh.getLastRowNum()) {throw new IllegalArgumentException("Attempting to write a row[" + rownum + "] " + "in the range [0," + this._sh.getLastRowNum() + "] that is already written to disk.");} else {//获取要创建得行数Row previousRow = rownum > 0 ? this.getRow(rownum - 1) : null;int initialAllocationSize = 0;if (previousRow != null) {initialAllocationSize = previousRow.getLastCellNum();}if (initialAllocationSize <= 0 && this._writer.getNumberOfFlushedRows() > 0) {initialAllocationSize = this._writer.getNumberOfCellsOfLastFlushedRow();}if (initialAllocationSize <= 0) {initialAllocationSize = 10;}SXSSFRow newRow = new SXSSFRow(this, initialAllocationSize);this._rows.put(new Integer(rownum), newRow);// 这儿进行了判断,如果当前行数大于randomAccessWindowSize ,则flushRows 刷新内存区域if (this._randomAccessWindowSize >= 0 && this._rows.size() > this._randomAccessWindowSize) {try {this.flushRows(this._randomAccessWindowSize);} catch (IOException var7) {throw new RuntimeException(var7);}}return newRow;}} else {throw new IllegalArgumentException("Invalid row number (" + rownum + ") outside allowable range (0.." + maxrow + ")");}}

根据官网得描述 他这个刷新应该是一行一行得进行刷新:
一个包含100行窗口的工作表。 当行数达到101时,rownum=0的行被刷新到磁盘并从内存中删除,当rownum达到102时,rownum=1的行被刷新,依此类推。

总结

工作原理:
缓冲和分段写入: 当创建 SXSSFWorkbook 对象时,它会创建一个基于硬盘的滑动窗口(window)。数据不会一次性全部写入内存,而是被分为一系列窗口(windows),每个窗口中包含一定数量的行。这样可以限制内存占用,只有当前窗口中的数据会被加载到内存中。

滑动窗口的使用: 当超过窗口容量时,SXSSF 将当前窗口中的数据写入到临时文件中,并将窗口滑动到下一段数据。这种方式实现了数据的分段处理和写入,减少了内存压力。

Flush 和 Close: 当操作完成后,需要调用 flush() 方法来强制将数据写入到临时文件中。最后,调用 close() 方法关闭 SXSSFWorkbook 对象,释放资源并删除临时文件。

实测25W行得报表是没有问题得

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

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

相关文章

网站高性能架构设计——高性能数据库集群

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、高性能数据库简介 1.高性能数据库方式 读写分离&#xff1a;将访问压力分散到集群中的多个节点&#xff0c;没有分散存储压力 分库分表&…

Maven 私服搭建

文章目录 配置模板servermirror RELEASE、SNAPSHOT版本区别发行版&#xff08;RELEASE&#xff09;快照&#xff08;SNAPSHOT&#xff09; mvn deploy 配置模板 server <!--第一个server-id要和下面的mirror中的id一致&#xff0c;代表拉取是也需要进行身份校验--> <…

Unity_使用FairyGUI搭建登录页面

Unity_使用FairyGUI搭建登录页面 1. 使用FairyGUI准备一个UI界面&#xff0c;例如&#xff1a;以下登录 2. 发布导出&#xff08;发布路径设置为Unity的Asset下任何路径&#xff09; 3. Unity编辑器安装FairyGUI包资源&#xff08;在资源商店找见并存储为我的资源&#xff0c;…

百度智能云战略与咨询高级总监詹颖:每个人都能在大模型驱动的数字化生态中找到立足之地

“ 大模型是皇冠上的明珠。 ” 整理 | 王娴 编辑 | 云舒 出品&#xff5c;极新 2023年11月28日&#xff0c;极新AIGC行业峰会在北京东升国际科学园顺利召开&#xff0c;百度智能云战略与咨询高级总监詹颖女士在会上做了题为《生成式 AI 驱动企业应用创新》的演讲。 重点…

了解宝宝健康第一步:做好华大基因无创产前筛查检测

近年来&#xff0c;高龄产妇明显增加&#xff0c;多因素的影响导致出生缺陷发生率呈总体上升趋势&#xff0c;出生缺陷已经成为重大公共卫生问题之一&#xff0c;更是影响人口质量的重要风险因素。孕前、孕期到产后的出生缺陷综合防控三级体系中&#xff0c;做好产前筛查是阻断…

python的运行原理

Python本身不能直接调动电脑的运行。但是&#xff0c;Python可以利用操作系统提供的接口来与计算机进行交互。比如&#xff0c;Python可以使用操作系统提供的API来执行某些任务&#xff0c;如创建、读取、修改、删除文件&#xff0c;启动程序或服务等。Python也可以利用第三方模…

通过fpmarkets与自媒体导师学习经验,避免踩坑

举一个例子&#xff0c;从fpmarkets与自媒体导师学习的负面经验&#xff0c;避免各位投资者踩坑。这个要从fpmarkets刚踏入外汇交易市场的第二年说起&#xff0c;偶然的一次&#xff0c;当fpmarkets看到一个可以不用花钱就可以学习交易培训课程时&#xff0c;就如同中了大奖一样…

高效记住GDI+常用绘图

1. 绘图质量&#xff1a;设置Graphics属性 主要有&#xff1a;根据首字母简写为&#xff1a;ISCT (您可以记为: Is CT?——引伸记忆&#xff1a;是否CT检查&#xff1f; 【CT为医院的“CT检查”&#xff0c;这里为检查绘图质量】 比如要获得最高质量的图像&#xff0c;可以…

股票关键指标

股票市场有许多关键指标&#xff0c;投资者通常使用这些指标来评估一支股票的潜在价值、风险和投资机会。以下是一些常见的股票关键指标&#xff1a; 1. 市盈率&#xff08;P/E比&#xff09;&#xff1a; 衡量一支股票当前价格与每股收益之比&#xff0c;是评估股票相对估值的…

【STM32单片机】贪吃蛇游戏设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使用IIC OLED模块、按键等。 主要功能&#xff1a; 系统运行后&#xff0c;OLED显示游戏界面&#xff0c;可通过K1-K4键控制蛇的方向&#xff0c;当蛇吃…

【腾讯云 HAI域探秘】借助高性能服务HAI快速学会Stable Diffusion生成AIGC图片——必会技能【微调】

目录 Stable Diffusion基本使用方法 学术加速测试 配置中文插件 Prompt与Negative prompt 采样器说明 人像生成 水光效果 微调的使用 图像生成种子/seed使用 附加/Extra 微调实例测试 图生图微调 ​编辑 使用蒙版微调 Stable Diffusion基本使用方法 环境配置&am…

记录每日LeetCode 2697.字典序最小回文串 Java实现

题目描述&#xff1a; 给你一个由 小写英文字母 组成的字符串 s &#xff0c;你可以对其执行一些操作。在一步操作中&#xff0c;你可以用其他小写英文字母 替换 s 中的一个字符。 请你执行 尽可能少的操作 &#xff0c;使 s 变成一个 回文串 。如果执行 最少 操作次数的方案…

2023-12-12 AIGC-AI在理解用户提问时的局限性和误解领域

摘要: 2023-12-12 AIGC-AI在理解用户提问时的局限性和误解领域 AI在理解用户提问时的局限性和误解领域 局限性: AI在理解用户提问时的局限性和误解领域是多方面的&#xff0c;这些限制通常源于技术的本质、训练数据的特性以及AI模型的设计。下面详细讨论这些方面&#xff1a;…

【机器学习】亚马逊云科技基础知识:以推荐系统为例。你知道机器学习的关键所在么?| 机器学习管道的各个阶段及工作:以Amazon呼叫中心转接问题为例讲解

有的时候,暂时的失利比暂时胜利要好得多。 ————经典网剧《mao pian》,邵半仙儿 🎯作者主页: 追光者♂🔥 🌸个人简介: 💖[1] 计算机专业硕士研究生💖 🌿[2] 2023年城市之星领跑者TOP1(哈尔滨)🌿 🌟[3] 2022年度博客之星人工智能领域TOP

正交基概念

求正交向量组中的系数 考虑 n n n 个任意两个向量之间相互正交的 n n n 维向量 a ⃗ \vec a a &#xff0c;则其构成一个 n n n 维的欧几里得空间 R n R^n Rn&#xff0c;为其中的每一个向量赋予一个常数系数 c c c&#xff0c;则空间中的任意向量 v v v 可以表示为这组…

大象慧云:从设立分部到迁移总部 与贵阳贵安共筑税务数字化未来

近年来&#xff0c;贵阳贵安着力提升政务服务水平&#xff0c;通过擦亮“贵人服务”品牌&#xff0c;持续优化营商环境。在这样的环境下&#xff0c;再加上“大数据基因”&#xff0c;对于希望在大数据领域大展拳脚的企业来说&#xff0c;贵阳贵安无疑成为了一个极具吸引力的选…

swiper播放视频,完成后自动切换下一张

video 属性和事件用法大全&#xff1a; https://www.cnblogs.com/rogerwu/p/10072119.html 我的思路是监听视频播放进度&#xff0c;如果播放完毕再开启swiper的自动轮播&#xff0c;因为我的需求是只有第一个swiper才是视频&#xff0c;后边的都是图片&#xff0c;那就需要轮…

【ZYNQ】AXI4总线接口协议学习

建议翻看着底部的参考文档资料和本文一起辅助阅读 本文带你详细的了解AXI总线协议&#xff0c;并且基于官方手册&#xff0c;能够提高你的手册阅读能力。 什么是AXI AXI 的英文全称是 Advanced eXtensible Interface&#xff0c;即高级可扩展接口&#xff0c;它是 ARM 公司所提…

自激活T细胞为肿瘤免疫治疗提供新思路—高分文献分享

CD28是在所有小鼠和人类T细胞上表达的共刺激受体&#xff0c;用来调节T细胞受体(TCR) 的响应。异常的CD28 信号传导是癌症、自身免疫和病毒感染中T细胞功能障碍的决定性特征之一。早期的一些研究表明CD28对CD4 T细胞更重要&#xff0c;但也有越来越多的研究者发现其对CD8 T细胞…

HAT(CVPR 2023):Hybrid Attention Transformer for Image Restoration

HAT ​ 论文地址&#xff1a;HAT: Hybrid Attention Transformer for Image Restoration ​ 代码地址&#xff1a;XPixelGroup/HAT: CVPR2023 - Activating More Pixels in Image Super-Resolution Transformer 摘要 ​ 通过归因分析attribution analysis method - Local …