Java读取操作大数据excel

2023-11-14

工作需要,读取大数据量的excel。用Apache poi的普通模式读取,会抛内存溢出。查询文档得知有另外一种模式--用户模式。该模式不会一下子整个文件load进来放在内存里,而是一行一行的读取,这样就能避免内存溢出了。

上码:

package com.ism.excel.pkg07;

import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 * XSSF and SAX (Event API)
 */
public abstract class XxlsAbstract extends DefaultHandler {
	private SharedStringsTable sst;
	private String lastContents;
	private boolean nextIsString;

	private int sheetIndex = -1;
	private List<String> rowlist = new ArrayList<String>();
	private int curRow = 0;		//当前行
	private int curCol = 0;		//当前列索引
	private int preCol = 0;		//上一列列索引
	private int titleRow = 0;	//标题行,一般情况下为0
	private int rowsize = 0;	//列数
	

	//excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型
	public abstract void optRows(int sheetIndex,int curRow, List<String> rowlist) throws SQLException;
	
	//只遍历一个sheet,其中sheetId为要遍历的sheet索引,从1开始,1-3
	/**
	 * 
	 * @param filename
	 * @param sheetId  sheetId为要遍历的sheet索引,从1开始,1-3
	 * @throws Exception
	 */
	public void processOneSheet(String filename,int sheetId) throws Exception {
		OPCPackage pkg = OPCPackage.open(filename);
		XSSFReader r = new XSSFReader(pkg);
		SharedStringsTable sst = r.getSharedStringsTable();
		
		XMLReader parser = fetchSheetParser(sst);

		// rId2 found by processing the Workbook
		// 根据 rId# 或 rSheet# 查找sheet
		InputStream sheet2 = r.getSheet("rId"+sheetId);
		sheetIndex++;
		InputSource sheetSource = new InputSource(sheet2);
		parser.parse(sheetSource);
		sheet2.close();
	}

	/**
	 * 遍历 excel 文件
	 */
	public void process(String filename) throws Exception {
		OPCPackage pkg = OPCPackage.open(filename);
		XSSFReader r = new XSSFReader(pkg);
		SharedStringsTable sst = r.getSharedStringsTable();

		XMLReader parser = fetchSheetParser(sst);

		Iterator<InputStream> sheets = r.getSheetsData();
		while (sheets.hasNext()) {
			curRow = 0;
			sheetIndex++;
			InputStream sheet = sheets.next();
			InputSource sheetSource = new InputSource(sheet);
			parser.parse(sheetSource);
			sheet.close();
		}
	}

	public XMLReader fetchSheetParser(SharedStringsTable sst)
			throws SAXException {
		XMLReader parser = XMLReaderFactory.createXMLReader();
				//.createXMLReader("org.apache.xerces.parsers.SAXParser");
		this.sst = sst;
		parser.setContentHandler(this);
		return parser;
	}

	public void startElement(String uri, String localName, String name,
			Attributes attributes) throws SAXException {
		// c => 单元格
		if (name.equals("c")) {
			// 如果下一个元素是 SST 的索引,则将nextIsString标记为true
			String cellType = attributes.getValue("t");
			String rowStr = attributes.getValue("r");
			curCol = this.getRowIndex(rowStr);
			if (cellType != null && cellType.equals("s")) {
				nextIsString = true;
			} else {
				nextIsString = false;
			}
		}
		// 置空
		lastContents = "";
	}

	public void endElement(String uri, String localName, String name)
			throws SAXException {
		// 根据SST的索引值的到单元格的真正要存储的字符串
		// 这时characters()方法可能会被调用多次
		if (nextIsString) {
			try {
				int idx = Integer.parseInt(lastContents);
				lastContents = new XSSFRichTextString(sst.getEntryAt(idx))
						.toString();
			} catch (Exception e) {

			}
		}

		// v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引
		// 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
		if (name.equals("v")) {
			String value = lastContents.trim();
			value = value.equals("")?" ":value;
			int cols = curCol-preCol;
			if (cols>1){
				for (int i = 0;i < cols-1;i++){
					rowlist.add(preCol,"");
				}
			}
			preCol = curCol;
			rowlist.add(curCol-1, value);
		}else {
			//如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法
			if (name.equals("row")) {
				int tmpCols = rowlist.size();
				if(curRow>this.titleRow && tmpCols<this.rowsize){
					for (int i = 0;i < this.rowsize-tmpCols;i++){
						rowlist.add(rowlist.size(), "");
					}
				}
				try {
					optRows(sheetIndex,curRow,rowlist);
				} catch (SQLException e) {
					e.printStackTrace();
				}
				if(curRow==this.titleRow){
					this.rowsize = rowlist.size();
				}
				rowlist.clear();
				curRow++;
				curCol = 0;
				preCol = 0;
			}
		}
	}

	public void characters(char[] ch, int start, int length)
			throws SAXException {
		//得到单元格内容的值
		lastContents += new String(ch, start, length);
	}
	
	//得到列索引,每一列c元素的r属性构成为字母加数字的形式,字母组合为列索引,数字组合为行索引,
	//如AB45,表示为第(A-A+1)*26+(B-A+1)*26列,45行
	public int getRowIndex(String rowStr){
		rowStr = rowStr.replaceAll("[^A-Z]", "");
		byte[] rowAbc = rowStr.getBytes();
		int len = rowAbc.length;
		float num = 0;
		for (int i=0;i<len;i++){
			num += (rowAbc[i]-'A'+1)*Math.pow(26,len-i-1 );
		}
		return (int) num;
	}

	public int getTitleRow() {
		return titleRow;
	}

	public void setTitleRow(int titleRow) {
		this.titleRow = titleRow;
	}
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java读取操作大数据excel 的相关文章

  • 如何使用Excel的墨迹工具添加手写签名?

    我想在我公司的一些表格中添加手写数字签名 目标是选择一个文档 添加签名 通过使用绘图板 这可以使用 Excel 的墨水工具完成 并将文件作为 PDF 存储在服务器中 这将消除打印然后扫描表格以获得签名的必要性 我使用 Excel 作为文件操
  • 按字母顺序对组合框值进行排序

    我的 Excel 用户表单中有一个组合框 按字母顺序排序的最简单方法是什么 它的值是在 vba 中硬编码的 新的值只是添加到底部 因此它们不按任何顺序排列 当前正在使用用户表单 以便我们的用户可以将数据从我们的数据库导入到 Excel 中
  • Excel 公式转 SUMIF 日期属于特定月份

    我有以下格式的 Excel 数据 Date Amount 03 Jan 13 430 00 25 Jan 13 96 00 10 Jan 13 440 00 28 Feb 13 72 10 28 Feb 13 72 30 仅当月份位于时 我
  • 绘制持续时间图表

    从我在写这篇文章之前所做的阅读中 我相当确定我需要创建甘特图 但我不知道这是否是正确的路线 需要将开始时间和结束时间的数据作为一个单位绘制在 Excel 图表上 Y 轴为日期 X 轴为一天中的小时 开始时间和结束时间的格式是 Excel 数
  • 将整个工作表复制到 Excel 2010 中的新工作表

    我发现了类似的问题 涉及复制一个工作簿中的整个工作表并将其粘贴到另一个工作簿 但我感兴趣的是简单地复制整个工作表并将其粘贴到同一工作簿中的新工作表 我正在将 2003 xls 文件转换为 2010 xlsm 用于在工作表之间复制和粘贴的旧方
  • 从 excel/vba 生成电子邮件到 Outlook 时,我的电子邮件签名不会出现?

    您好 我使用 Ron De Bruin 的精彩网站创建了 VBA 代码 该代码可以从 Excel 文件生成向特定用户发送的电子邮件 唯一的问题是我的签名没有出现在每封电子邮件上 而且我似乎找不到如何在代码中添加它 有人可以建议吗 正如你所知
  • VBA 按用户范围选择排序

    在过去的三天里我一直在为这个问题苦苦挣扎 所以请帮忙 我想做的是当我运行 Macro1 时 为了论证 将弹出窗口以选择应排序的单元格范围 通过选择的最后一列 或第五列 对这些进行排序 从最低数字到最高数字 这里的问题是所选区域每次都会改变
  • Excel VBA - 以编程方式列出用户窗体上控件的可用事件过程

    你好 我已经搜索过 google 但发现只有 1 页提到了如何在 MS Access 中执行此操作 但没有在 MS Excel 中执行此操作 此处 列出 MS Access 表单的控件及其事件 https stackoverflow com
  • 从 Excel 将参数传递到 SQL Server 上的 MS Query 中的临时变量

    我已经使用 Microsoft 查询创建了参数查询 如上所述here https superuser com questions 197453 run an sql query with a parameter from excel 200
  • 在一个单元格中显示两个日期

    我正在尝试在 Excel 的一个单元格中显示两个日期 我使用了以下公式 DATE YEAR NOW MONTH NOW I1 DATE YEAR NOW MONTH NOW I15 其中I1和I15的值分别为1和15 我选择这个公式的原因是
  • PHP Microsoft Excel 文件生成/导出类

    我一直在寻找一个好的 Excel 文件生成类 但还没有找到 我的首要问题是 虽然我可以在 Excel 中打开导出的文件 运行 2007 年 但我总是收到一条警告 文件的格式与文件扩展名不同 我注意到 phpMyAdmin 中的 Excel
  • 使用Excel宏执行命令并关闭cmd窗口

    这是我现在正在尝试的 Sub del BJSFM files Call Shell cmd exe S K cd d C UTAS SA del f s q BJSFM gt nul vbNormalFocus End Sub 问题是命令窗
  • Python:使用Excel CSV文件仅读取某些列和行

    虽然我可以读取 csv 文件而不是读取整个文件 但如何仅打印某些行和列 想象一下这是 Excel A B C D E State Heart Disease Rate Stroke Death Rate HIV Diagnosis Rate
  • 使用VBA删除Excel中的非重复数据

    我尝试删除非重复数据并保留重复数据 我已经完成了一些编码 但什么也没发生 哦 这是错误 哈哈 这是我的代码 Sub mukjizat2 Dim desc As String Dim sapnbr As Variant Dim shortDe
  • 当应用程序继续运行时,如何清理 .NET 中的 COM 引用?

    我正在开发一个 NET 程序 该程序启动 Excel 的新实例 执行一些工作 然后结束 但必须让 Excel 保持运行 稍后 当程序再次运行时 它将尝试挂钩到前一个实例 在这种情况下处理 COM 对象释放的最佳方法是什么 如果我第一次没有对
  • Excel的解析路径

    其实我想问以下问题 对于位于 目录中定义的 PATH 怎么能 我找出这些目录中的哪个 找到了 因为我需要使用 Process Run 从 C 运行 Excel 并且只需指示 Excel 即可正常工作 Windows 似乎知道在哪里可以找到它
  • 使用 UiPath 循环 Excel 文件中的 URL

    我尝试了几种方法 但不知怎的 它们看起来不干净 我有一个 Excel 格式的 URL 文件 一列中有 400 多个 URL 我希望 UiPath 从该文件中读取并一一浏览这些 URL 我尝试让 导航到 从从 Excel 读取的变量中读取 但
  • 在 Excel 中的文件夹内的所有文件上添加一列

    我在一个文件夹内有 250 个不同的 excel 文件 具有相同的布局 其中包含列A to F 我需要在列上添加新列G 传统的方法是打开每个文件并在以下位置添加新列G 有没有使用 Excel 宏或任何其他工具的简单过程来完成此任务 这个链接
  • WebAPI 和 Angular JS Excel 文件下载 - 文件损坏

    我正在 WebAPI 中生成 Excel 文件 我将其 存储 在内存流中 然后放入响应 如下所示 var result new HttpResponseMessage HttpStatusCode OK Content new Stream
  • xlwt 可以在单元格中创建一个包含标题和链接变量的超链接吗?

    例如 如何更改以下行 使 test 为变量 T 且 http google com http google com 是变量L ws write 0 0 xlwt Formula test HYPERLINK http google com

随机推荐

  • Doris之Binlog Load

    Binlog Load Binlog Load提供了一种使Doris增量同步用户在Mysql数据库的对数据更新操作的CDC Change Data Capture 功能 适用场景 INSERT UPDATE DELETE支持 过滤Query
  • Qt6教程之三(3) QtWedget自定义控件

    在之前的博客中 我们使用的控件都是Qt官方提供的 对于控件的特性也只能被动地接受 为了打破这种束缚 可以按照自己的想法来定义控件 不过自定义控件必须遵守Qt官方的一套自定义控件规则 在规则之下我们就可以定义属于我们自己的控件啦 QWidge
  • 输出比较实验

    转载链接 输出比较 输出比较就是通过定时器的外部引脚对外输出控制信号 输出比较的模式有哪些 可以设置为以下几种不同的模式 翻译如下 000 冻结 输出比较寄存器TIMx CCR1中的内容与计数器TIMx CNT中的内容之间的比较对输出无影响
  • jquery ajax 无效字符,【JQuery】 ajax 无效的JSON基元

    如题 个人理解就是 你向传数据 josn格式 了 但是后台接受确不是json格式的 数据 贴段代码 var strJson usercode 123 password 123 ajax type POST url Index doLogin
  • CentOS7下安装 mysql5.7.25(glibc版)(可用)

    一 安装前的检查 1 检查 linux 系统版本 root localhost cat etc system release 2 检查是否安装了 mysql mysql 有三种安装方式 二进制包安装 RPM包安装 源码装 3 系统内存检查
  • c++的cout输出

    1 c 的cout输出顺序是从左往右进行输出 但是是从右往左压入栈 2 c 的cout的输出是遇到函数是若函数内右cout的操作则立即执行 3 不同编译器对相同语句的编译规则是不一样的 所以最好不要对同一变量进行多次的修改 也不用深究 没有
  • go语言如何编译为可执行文件

    使用系统自带的cmd找到main函数所在位置 1 go build go即可把go程序编译成exe文件 2 go run go就可以运行go程序了 3 便宜源代码 官方说使用go build fileName 编译出来的就直接带有调试信息了
  • bash: ifconfig: 未找到命令 解决方案

    解决思路 1 ifconfig 命令存在的情况 首先查看 ifconfig 命令在哪个目录下 顺便检查是否安装了这个命令 whereis ifconfig 然后查看 echo PATH PATH 中是否包含了这个目录 一般情况下是不包含的
  • 前端开发都需要掌握那些技术?

    前端技术多且杂 那么作为前端开发者 我们可以从那些方面进行进阶提升呢 本文从以下几个方面进行了整理归纳 内容如下 一 网页开发 二 小程序 三 移动端 四 桌面端 五 其他技术 一 网页开发 这里指PC端网页开发 要求的技术主要有以下几类
  • 华为OD机试(JAVA)真题 -- 最长(连续)子串

    import java util Scanner 给定一个字符串 只包含字母和数字 按要求找出字符串中的最长 连续 子串 字符串本身是其最长的子串 子串要求 只包含 1 个字母 a z A Z 其余必须是数字 字母可以在子串中的任意位置 如
  • shell自动部署docker及docker-compose

    一 准备环境 centos7 6及centos7 9已通过测试 测试时服务器刚刚完成初始化 未修改任何配置 可以直接运行脚本进行安装 要求主机可以访问互联网 yum环境在脚本中已自动准备 将两个脚本直接复制放到root目录下 赋予可执行权限
  • NGUI学习笔记汇总

    NGUI学习笔记汇总 适用于NGUI2 x NGUI3 x 一 NGUI的直接用法 1 Attach a Collider 表示为NGUI的某些物体添加碰撞器 如果界面是用NGUI做的 只能这样添加 注 用Component添加无效 2 A
  • 前端WEB安全

    一 浏览器安全 首先了解前端web安全知识 比不可绕开的基础就是同源策略了 同源策略 Same Origin Policy 是一种约定 它是浏览器最核心也最基本的安全功能 如果缺少了同源策略 则浏览器的正常功能可能都会受到影响 可以说Web
  • 你想改变现在的生活吗?

    你想改变现在的生活吗 你想加薪吗 想买车吗 想找到你生命中的另一半吗 去学习吧 学校是个神奇的地方
  • 记一次解决联想笔记本冬天卡顿反应慢的方法

    个人简介 个人主页 九黎aj 幸福源自奋斗 平凡造就不凡 如果文章对你有用 麻烦关注点赞收藏走一波 感谢支持 欢迎订阅我的专栏 autojs 图携带方便买了一个联想笔记本 然后发现笔记本充电时候正常 不卡 不充电时候会卡0 4Ghz ctr
  • Java包装类、自动装箱与拆箱知识总结

    因为在学习集合时知道集合里存放的对象都是Object类型 取出的时候需要强制类型转换为目标类型 使用泛型集合不需要 如int a Integer arrayList get 0 然后我们就会发现 为什么要强制转换为Integer 而不是in
  • C++中const,指针和引用

    C 中的const 指针和引用 在线C C 编译器 可以试着运行代码 C 中的const 在C语言中 const修饰的量称为常变量 在编译过程中 const就是当成变量的编译生成指令的 不可以直接修改它的值 但是可以通过地址进行修改其对应的
  • springmvc 获取项目中的所有请求路径

    springboot springmvc 获取项目中的所有请求路径 1 编写业务代码 Autowired private WebApplicationContext applicationContext GetMapping getAllU
  • 关于vue2中$set及$delete的使用

    this set的使用 在平时使用vue进行开发的时候 我经常会遇到一个这样的问题 就是当data中包含声明且已赋值的对象或者数组 数组包对象 时 我们要向当前的这个对象中添加一个新的属性并且更新 结果发现并不会更新视图 只在控制台打印
  • Java读取操作大数据excel

    工作需要 读取大数据量的excel 用Apache poi的普通模式读取 会抛内存溢出 查询文档得知有另外一种模式 用户模式 该模式不会一下子整个文件load进来放在内存里 而是一行一行的读取 这样就能避免内存溢出了 上码 package