【✅如何针对大Excel做文件读取?】

news2024/10/7 4:27:19

在这里插入图片描述

✅如何针对大Excel做文件读取?

  • 🟩如何针对大Excel做文件读取
    • 🟩XSSFWorkbook文件读取
    • 🟩EasyExcel文件读取
  • ✅扩展知识
    • 🟩 EasyExcel简介
    • 🟩EasyExcel 为什么内存占用小?

🟩如何针对大Excel做文件读取

在POI中,提供了SXSSFWorkbook,通过将部分数据写入磁盘上的临时文件来减少内存占用。但是SXSSFWorkbook只能用于文件写入,但是文件读取还是不行的,就像我们前面分析过的,Excel的文件读取还是会存在内存溢出的问题的。

🟢参考本人博客文件处理专栏: 什么是POI,为什么他会导致内存溢出?

🟢参考本人博客文件处理专栏: POI如何做大文件的写入?

那如果要解决这个问题,可以考虑使用EasyExcel。

EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。他能让你在不用考虑性能、
内存的等因素的情况下,快速完成Excel的读、写等功能。

关于使用XSSFWorkbook和EasyExcel的文件读取,我这里也做了个内存占用的对比:

🟩XSSFWorkbook文件读取

读取一个27.3MB的文件(文件的生成代码📑✅链接: POI如何做大文件的写入)

package excel.read;

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 XSSFExcelReadTest {
	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);

			// foreach 遍历所有行
			for (Row row : sheet) {
				// 遍历所有单元格
				for (Cell cell : row) {
					// 根据不同数据类型处理数据
					switch (cel1.getCel1Type()) {
						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();
		}
	}
}

同样使用Arthas查看内存占用情况:

在这里插入图片描述
占用内存1000+M

🟩EasyExcel文件读取

package excel.read;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener:

public class EasyExcelReadTest {

	public static void main(Stringl] args) {
		
		// 指定要读取的文件路径
		String filename = "example.xlsx";

		EasyExcel.read(filename, new PrintDataListener()).sheet().doRead();
	}
}

// 监听器,用于处理读取到的数据
class PrintDatalistener implements ReadListener<Object> {
	@Override
	public void invoke(Object data, AnalysisContext context) {
		//处理每一行的数据
		System.out.println(data) ;
	}
	
	@Override
	public void doAfterAllAnalysed(AnalysisContext context) {
		// 所有数据解析完成后的操作
	}

	@Override
	public void onException(Exception exception, AnalysisContext context) throws Exception {
		//处理读取过程中的异常
	}
}

同样使用Arthas查看内存占用情况:

在这里插入图片描述
内存占用只有不到100MB。

✅扩展知识

🟩 EasyExcel简介

EasyExcel是一款软件程序,允许用户创建、编辑和分析电子表格。它设计成用户友好和直观,使得所有技能水平的用户都能轻松处理数据。EasyExcel提供了广泛的功能,包括进行计算、创建图表和图形以及在表格中组织数据的能力。它还支持各种文件格式,如.xls和.xlsx,使用户能够方便地导入和导出来自其他应用程序的数据。总体而言,EasyExcel是一种多功能的工具,用于管理和操作电子表格格式的数据。

🟩EasyExcel 为什么内存占用小?

EasyExcel是一款基于POI(Apache开源的Java类库)开发的Excel操作工具。相比于传统的操作Excel的方式,EasyExcel采用了一种新的处理方式,即将Excel数据转化为对象列表然后进行操作。这种方式减少了对内存的占用,提高了数据处理的效率。

具体的来说,EasyExcel在内存占用方面有以下几个优势:

1. 逐行读写:EasyExcel通过逐行读写的方式操作Excel,即一次只读取或写入一行数据,而不是一次性读取或写入整个文件。这样可以大大减少对内存的占用。

2. 分段读写:当需要处理大文件时,EasyExcel可以将文件拆分成多个小段进行读写,每次只处理一小段数据,将读写的内存压力均匀分散,降低了内存的占用。

3. 内存缓冲区:EasyExcel内部使用了内存缓冲区来存储读取或写入的数据,通过合理控制缓冲区的大小,可以有效地减少对内存的占用。

4. 高效的数据处理算法:EasyExcel内部采用了高效的数据处理算法,例如使用零拷贝技术来提高数据读写的速度,减少对内存的占用。

综上所述,EasyExcel通过优化读写方式、使用内存缓冲区和高效的数据处理算法等手段,可以实现在相同数据量的情况下占用更小的内存空间,提高数据处理的效率。

参考代码,展示了如何使用EasyExcel读取Excel文件并计算内存占用。

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.ReadListener;

import java.io.File;

public class EasyExcelMemoryDemo {

    public static void main(String[] args) {
        String filePath = "path/to/excel/file.xlsx";

        // 创建一个监听器,用于统计内存占用
        ReadListener<Object> listener = new ReadListener<>() {
            private long startMemory;

            @Override
            public void invoke(Object data, AnalysisContext context) {
                if (context.readRowHolder().getRowIndex() == 0) {
                    // 记录读取第一行数据时的内存占用
                    startMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                // 读取完所有数据后,计算内存占用的差值
                long endMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
                long memoryUsage = endMemory - startMemory;

                System.out.println("Excel文件读取完毕");
                System.out.println("内存占用差值:" + memoryUsage + " bytes");
            }
        };

        // 读取Excel文件
        EasyExcel.read(new File(filePath)).registerReadListener(listener).sheet().doRead();
    }
}

输出Excel文件读取完毕后的内存占用差值。相比于使用传统的POI工具,使用EasyExcel读取Excel文件时,内存占用会更小。

EasyExcel是一个Java库,用于简化Excel文件的读写操作。相较于Apache POI等传统Excel处理库,EasyExcel具有内存占用小的优势。这主要归功于EasyExcel的底层实现和数据处理方式。

展示:

import com.alibaba.excel.EasyExcel;  
import com.alibaba.excel.ExcelReader;  
import com.alibaba.excel.ExcelWriter;  
import com.alibaba.excel.context.AnalysisContext;  
import com.alibaba.excel.event.AnalysisEventListener;  
import com.alibaba.excel.metadata.BaseRowModel;  
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;  
import com.alibaba.excel.write.metadata.WriteSheet;  
import com.alibaba.excel.write.metadata.WriteTable;  
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;  
  
import java.util.ArrayList;  
import java.util.List;  
  /**
  *@author 昕宝爸爸爱编程
  *@date 23/12/14
  */
public class AdvancedMemoryOptimizedExample {  
    public static void main(String[] args) {  
        String inputFileName = "input_example_complex.xlsx";  
        String outputFileName = "output_example_complex.xlsx";  
        int pageSize = 1000;  
        int sheetCount = 3; // 定义要写入的Sheet数量  
        int totalPage = 0; // 总页数变量,用于动态计算总页数  
  
        // 创建数据模型类,用于存储读取到的数据  
        class DataModel extends BaseRowModel {  
            private String field1; // 字段1  
            private int field2; // 字段2  
            // 其他字段...  
            // 对应的getter和setter方法...  
        }  
  
        // 内存优化示例:读取Excel文件并分页处理  
        List<DataModel> dataList = new ArrayList<>(); // 创建一个空的列表用于存储数据  
        ExcelReader excelReader = EasyExcel.read(inputFileName, new NoModelDataListener<DataModel>()).build(); // 使用自定义的DataModel类作为监听器的参数类型  
        ReadSheet readSheet = EasyExcel.readSheet(pageSize).build(); // 设置读取时的分页参数  
        excelReader.read(readSheet, new AnalysisEventListener<DataModel>() { // 使用自定义的DataModel类作为事件处理接口的参数类型  
            @Override  
            public void invoke(DataModel data, AnalysisContext context) {  
                // 在invoke方法中进行自定义数据处理逻辑,比如将读取到的数据存储到数据库等操作...  
                dataList.add(data); // 这里仅作示例,将读取到的数据添加到列表中,实际应用中可能需要进行其他处理  
            }  
            @Override  
            public void doAfterAllAnalysed(AnalysisContext context) {  
                // 处理读取完所有数据后的逻辑...可以在这里添加一些操作,比如关闭资源等  
                totalPage = context.getHead().getSheet().getVirtual(context).getTotalRowNum() / pageSize + 1; // 动态计算总页数,用于后续写入操作时使用  
            }  
        }); // 开始读取数据,并传入监听器进行数据处理  
        excelReader.finish(); // 读取完成后关闭Excel读取器  
  
        // 内存优化示例:写入Excel文件并自定义样式和分页写入策略  
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); // 创建一个自定义的单元格样式对象,可以根据需要设置样式属性  
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(null, contentWriteCellStyle); // 创建一个水平单元格样式策略对象,用于设置单元格样式策略  
        ExcelWriterBuilder writerBuilder = EasyExcel.write(outputFileName); // 创建Excel写入器构建器对象,用于配置写入参数和设置样式策略等  
        writerBuilder.registerWriteHandler(horizontalCellStyleStrategy); // 注册之前创建的样式策略对象到写入器中,用于设置单元格样式策略  
        ExcelWriter excelWriter = writerBuilder.build(); // 创建Excel写入器实例,用于实际写入操作  
        for (int i = 1; i <= sheetCount; i++) { // 根据定义的Sheet数量循环创建多个Sheet进行写入操作  
            WriteSheet writeSheet = EasyExcel.writerSheet("Sheet" + i).build(); // 创建多个Sheet进行写入操作,每个Sheet名称分别为"Sheet1"、"Sheet2"等,可以根据需要自定义Sheet名称和数量等参数  
            excelWriter.write(dataList, writeSheet, totalPage); // 将之前读取到的数据写入到输出文件中,并传入Sheet参数和样式策略等参数,同时传入动态计算的总页数参数,用于分页写入操作时使用  
        } // 循环写入多个Sheet数据到输出文件中,并传入对应的样式策略和总页数参数等

主要通过以下几个方式来节省内存:

使用分页读取和写入:通过设置pageSize参数,将数据分页读取和写入,可以减少一次性读取和写入的数据量,从而减少内存占用。

使用数据模型类:通过创建一个数据模型类(DataModel),将读取到的数据存储到该类的对象中,而不是直接存储到原始数据类型列表中。这样可以避免为每个数据项创建过多的对象,从而减少内存占用。

使用水平单元格样式策略:通过创建一个水平单元格样式策略对象(HorizontalCellStyleStrategy),并将样式策略注册到Excel写入器中。该策略可以根据单元格的内容自动应用样式,从而减少手动设置样式所带来的内存开销。

动态计算总页数:在读取完所有数据后,通过调用context.getHead().getSheet().getVirtual(context).getTotalRowNum()方法,动态计算总页数。这样可以避免在循环中多次计算总页数,从而减少内存占用。

综上所述,通过分页读取和写入、使用数据模型类、使用水平单元格样式策略以及动态计算总页数等方式,实现了内存的优化使用。

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

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

相关文章

JavaScript中的一些惊艳的编程技巧

你见过哪些令你膛目结舌的代码技巧&#xff1f; 代码世界有很多令人大呼小叫的技巧&#xff01;有的代码像魔术师一样巧妙地隐藏了自己&#xff0c;有的像魔法师一样让你眼花缭乱&#xff0c;还有的像瑜伽大师一样灵活自如。它们让我们惊叹不已&#xff0c;让我们觉得自己仿佛…

检测当前目录,将文件名输出到excel文件并建立链接

EXCEL是一个非常使用的软件,虽然我们平时仅使用他做一些报表,仅此而已; 我在工作中,由于很懒,不愿意做考试重复的工作,就想着使用vba的宏来完成重复的工作,这样就能省出一部分的时间来了。 本人不喜欢在博客里面写以下教程类的东西,我的理念是将工作中的痛点的解决办法…

我记不住的那些vim操作2

背景&#xff1a;最近在重新学习vi/vim&#xff0c;发现这个编辑器的用法真是太灵活了&#xff0c;所能掌控的也太多了&#xff0c;这次学习了一些之前没有学习过的内容&#xff0c;之前都是移动鼠标、编辑、复制、粘贴、保存等等(点我查看)&#xff0c;本次将介绍 标签、区域、…

设计模式-单例设计模式详解

生命无罪&#xff0c;健康万岁&#xff0c;我是laity。 我曾七次鄙视自己的灵魂&#xff1a; 第一次&#xff0c;当它本可进取时&#xff0c;却故作谦卑&#xff1b; 第二次&#xff0c;当它在空虚时&#xff0c;用爱欲来填充&#xff1b; 第三次&#xff0c;在困难和容易之…

一文图解 Transformer,小白也看得懂(完整版)

原作者&#xff1a;Jay Alammar 原链接&#xff1a;https://jalammar.github.io/illustrated-transformer 1.导语 谷歌推出的BERT模型在11项NLP任务中夺得SOTA结果&#xff0c;引爆了整个NLP界。而BERT取得成功的一个关键因素是Transformer的强大作用。谷歌的Transformer模型最…

043.Python异常处理_自定义上下文管理器

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

ESP32 核心闪存损坏

问题描述&#xff1a;使用Platform 开发ESP32-S3 报错通过串口打印报错提示为核心闪存损失具体报错如下。 ELF file SHA256: 25c739c3d81d8f15 E (183) esp_core_dump_flash: Core dump flash config is corrupted! CRC0x7bd5c66f instead of 0x0 Rebooting... ESP-ROM:esp32s3…

Python项目——表白照片墙

1、介绍 利用女神的照片&#xff0c;组成女神的名字&#xff0c;向女神表白。如下图&#xff1a; 原理&#xff1a;获取每个像素点的颜色&#xff0c;白色不贴图&#xff0c;黑色贴图。 2、工具 语言&#xff1a;python3.11编译器&#xff1a;PyCharm包&#xff1a;pygame p…

【IOS开发】传感器 SensorKit

资源 官方文档 https://developer.apple.com/search/?qmotion%20graph&typeDocumentation SensorKit 使应用程序能够访问选定的原始数据或系统从传感器处理的指标。 步骤信息加速度计或旋转速率数据用户手腕上手表的配置物理环境中的环境光有关用户日常通勤或旅行的详细…

java SpringCloud版本b2b2c鸿鹄云商平台全套解决方案

使用技术&#xff1a; Spring CloudSpring BootMybatis微服务服务监控可视化运营 B2B2C平台&#xff1a; 平台管理端(包含自营) 商家平台端(多商户入驻) PC买家端、手机wap/公众号买家端 微服务&#xff08;30个通用微服务如&#xff1a;商品、订单、购物车、个人中心、支…

项目实操四-性能测试过程实时监控分析

这里写目录标题 一、JMeter性能测试技巧1、CSV文件驱动2、定时器a、泊松随机定时器b、固定定时器c、高斯随机定时器d、均衡随机定时器e、同步定时器f、固定吞吐量定时器g、精准吞吐量定时器 3、全局变量 - 跨线程数据传递4、Debug调试器5、JMeter执行机端口被占用 二、JMeter性…

Linux集群实用脚本

现有三台虚拟机&#xff0c;例如&#xff1a;node2、node3、node4 三台虚拟机配置了免密登录&#xff0c;安装了hadoop等软件。 相关集群实用脚本命令 统一执行jps命令 jpsall #!/bin/bash ​ for host in node2 node3 node4 doecho $host ssh $host jps done ​ 统一执行命…

JVM日常故障排查小结

前置知识 jstack简介 jstack是JVM自带的工具&#xff0c;用于追踪Java进程线程id的堆栈信息、锁信息&#xff0c;或者打印core file&#xff0c;远程调试Java堆栈信息等。 而我们常用的指令则是下面这条: # 打印对应java进程的堆栈信息 jstack [ option ] pid option常见选…

AI摄影绘画与PS优化:重塑数字艺术的未来

文章目录 《AI摄影绘画与PS优化从入门到精通》内容简介作者简介楚天 目录前言/序言 在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的各个领域&#xff0c;包括艺术创作。AI摄影绘画和Photoshop&#xff08;PS&#xff09;优化是这个领…

[AI工具推荐]AiRestful智能API代码生成

智能API代码示例生成工具AiRestful 一、产品介绍二、如何使用1、第一步(必须):2、第二步(可选):3、第三步(智能生成): 三、如何集成到您的网站(应用)1、开始接入2、接入案例 四、注意点 一、产品介绍 AiRestful是一款基于智能AI的,帮助小白快速生成任意编程语言的API接口调用示…

中国经济增长:全球复苏的引擎

近年来&#xff0c;中国经济以其强劲的增长势头成为全球经济的重要引擎。中国的经济崛起不仅对自身国家发展具有重要意义&#xff0c;而且也对全球经济复苏和稳定有着积极影响。本文将从多个角度探讨中国经济增长对全球经济的影响及其作为全球复苏的引擎。 首先&#xff0c;中国…

基于SpringBoot的房屋租赁系统 附源码

基于SpringBoot的房屋租赁系统 附源码 文章目录 基于SpringBoot的房屋租赁系统 附源码 一.引言二.系统设计三.技术架构四.功能实现五.界面展示六.源码获取 一.引言 本文介绍了一个基于SpringBoot的房屋租赁系统。该系统利用SpringBoot框架的优势&#xff0c;实现了用户注册、登…

【C++】封装:练习案例-点和圆的关系

练习案例&#xff1a;点和圆的关系 设计一个圆形类&#xff08;Circle&#xff09;&#xff0c;和一个点类&#xff08;Point&#xff09;&#xff0c;计算点和圆的关系。 思路&#xff1a; 1&#xff09;创建点类point.h和point.cpp 2&#xff09;创建圆类circle.h和circle…

如何搭建企业管理系统Odoo并远程访问管理界面【内网穿透】

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…

SearchWP WordPress高级网站内容搜索插件(包含所有专业扩展)

点击阅读SearchWP WordPress高级网站内容搜索插件(包含所有专业扩展)原文 SearchWP WordPress高级网站内容搜索插件是一个非常强大的工具&#xff0c;可以显着增强您网站的搜索功能。通过向网站访问者提供高度相关和精确的搜索结果&#xff0c;它可以有效地简化他们的搜索过程…