当前位置: 首页 > news >正文

C# 实现完善 Excel 不规则合并单元格数据导入

 

目录

功能完善

Excel与DataSet的映射关系

运行环境

Excel DCOM 配置

设计实现

组件库引入

方法更新

返回值 

参数设计

打开数据源并计算Sheets

拆分合并的单元格

创建DataTable

将单元格数据写入DataTable

删除虚拟列 

总结


功能完善

在我的文章 《C#实现Excel合并单元格数据导入数据集》里讲述了可以将具有合并单元格的Excel文件数据导入到DataSet里,在实际使用情况中遇到如下情况,如下图:

如图中的 H 列,它是一个合并单元格,但它也属于一个特殊的单元格,即 worksheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell,Type.Missing) 最后一个内容单元格,由于其合并单元格的地址问题(),导入程序可能会计算成为一行数据:

如图 H1 列假设为标题列(字段名),那么 H2 列为数据行的第一行,作为最后一个单元格,因此可能会被识别为只有一行数据,而忽略后面所有的行。

因此比较快速的一种解决方案是在右侧增加一个虚拟列:

如图通过增加列标题(“虚拟列”)达到重新计算出 最后单元格 ,根据最后单元格的地址,可以计算出新的行数,以达到计算出正确行数据的目的。

Excel与DataSet的映射关系

下图是 Excel 与 DataSet 的映射关系图:

1、Excel应用的Workbook对象与 DataSet 同为容器对象

2、Worksheets和Tables均代表各自的表集合

3、Worksheet与Table进行对应,产生和导入实际的数据

运行环境

操作系统: Windows Server 2019 DataCenter

操作系统上安装 Office Excel 2016

.net版本: .netFramework4.7.1 或以上

开发工具:VS2019  C#

Excel DCOM 配置

请参考我的文章《C# 读取Word表格到DataSet》有对Office DCOM详细配置介绍,这里不再赘述,Excel的对应配置名称如下图所示:

  

设计实现

组件库引入

方法更新

设计  object[] ExcelAsDataSet(string _filename,bool hastitle,string startaddress,string endaddress) 方法

返回值 

方法返回object数组,共包括两个object对象,如果成功转化则 object[0] 存储 DataSet对象,否则为 null。如果不成功则 object[1] 存储string 错误信息对象,可根据object[1].ToString()!="" 来判断是否转化成功。

参数设计
  1. string _filename:Excel 数据源文件路径
  2. bool hastitle: 是否包含标题,如果设置为true,则表示首行数据为列名称定义
  3. string startaddress:可指定有效的起始单元格地址,不设置则默认为“A1”(即第一个单元格)
  4. string endaddress:可指定有效的截止单元格地址,不设置则默认为最后一个有值单元格(即XlCellType.xlCellTypeLastCell 枚举) 

    通过3、4参数的定义,可以定义出有效的导入矩形区域。

打开数据源并计算Sheets

			object[] rv=new object[2];rv[0]=null;rv[1]="";//创建一个名为ExcelApp的组件对象
//			ExcelApplication excel = new ExcelApplication();Excel.Application excel = new Excel.Application();excel.DisplayAlerts=false;excel.AskToUpdateLinks=false;Excel.Workbook xb=excel.Workbooks.Add(_filename);
//获取活动的 worksheet和 excel sheet的个数,准备遍历sheetsWorksheet worksheet = (Worksheet) excel.ActiveSheet;sheetCount=excel.Sheets.Count;  int	startSheetIndex=1;int	endSheetIndex=sheetCount;DataSet ds=new DataSet();
//遍历sheetsfor (int currentIndex = startSheetIndex; currentIndex <= endSheetIndex; currentIndex++){worksheet = (Worksheet)excel.Worksheets[currentIndex];worksheet.Activate();//处理每一个sheet.....}

拆分合并的单元格

在获取有效的单元格区域后,就开始遍历单元格对象,判断单元格对象 MergeCells 属性即可,判断 Cell.MergeCells.ToString() == "True"  即表示该单元格为合并单元格对象。

示例代码如下:

//获取起始单元和截止单元格,以确定有效区域Excel.Range _startcell=worksheet.Range["A1","A1"]; //默认为第一个单元格if(startaddress!=""){try{_startcell=worksheet.Range[startaddress,startaddress];}catch(Exception ex){rv[1]+=string.Format("{1}指定的起始单元格地址{0},不是合法的地址。\r\n",startaddress,worksheet.Name);//					KillProcessByStartTime("EXCEL",beforetime,aftertime);continue;}}Excel.Range _lastcell=worksheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell,Type.Missing);
//默认获取有值的最后一个有效的单元格excel.Cells[1, _lastcell.Column + 1] = "vcol"+ (_lastcell.Column + 1).ToString();_lastcell = worksheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);if(endaddress!=""){try{_lastcell=worksheet.Range[endaddress,endaddress];}catch(Exception ex){rv[1]+=string.Format("{1}指定的结束单元格地址{0},不是合法的地址。\r\n",endaddress,worksheet.Name);//					KillProcessByStartTime("EXCEL",beforetime,aftertime);//						return rv;continue;}}//遍历有效区域单元格foreach (Excel.Range aicell in worksheet.Range[_startcell,_lastcell]){if (aicell.MergeCells.ToString() == "True"){//处理合并单元格object temp_merge_value = aicell.Value2; //备份单元格的值int u_row = aicell.Row;  //记录单元格的首行索引int u_rows = aicell.MergeArea.Rows.Count; //记录单元格的合并区域包含的行数int u_col = aicell.Column; //记录单元格的首列索引int u_cols = aicell.MergeArea.Columns.Count; //记录单元格的合并区域包含的列数aicell.MergeArea.UnMerge();  //取消合并,拆分单元格Excel.Range new_aicell = worksheet.Range[worksheet.Cells[u_row, u_col], worksheet.Cells[u_row + u_rows - 1, u_col + u_cols - 1]];  //获取拆分后单元格后的有效区域new_aicell.Value2 = temp_merge_value; //将拆分的单元格重新赋值(备份值)}}

程序中通过 excel.Cells[1, _lastcell.Column + 1] = "vcol"+ (_lastcell.Column + 1).ToString(); 设置增加虚拟列列名,以达到重新计算最后单元格的目的。

创建DataTable

如果首行是列数据,则以该行的值创建表结构,否则自动创建以“C”为前缀的列名,如C1、C2...Cn以此类推。

				System.Data.DataTable dt=ds.Tables.Add();dt.TableName=worksheet.Name;  //表名为worksheet的名称for(int i=_startcell.Column;i<=_lastcell.Column;i++){Excel.Range _cell=worksheet.Range[worksheet.Cells[_startcell.Row,i],worksheet.Cells[_startcell.Row,i]];string _colname=hastitle==true?_cell.Value2.ToString():"C"+(i-_startcell.Column+1).ToString(); //如果第一行是标题,则赋单元格的值,否则以C开头加序号DataColumn dc=dt.Columns.Add();dc.ColumnName=_colname;dc.DataType=System.Type.GetType("System.String");dc.AllowDBNull=true;}

将单元格数据写入DataTable

object[,] cells=null;  定义二维对象数组if(hastitle) //如果首行包含列,则加行索引加1取数据行{startrow=_startcell.Row+1;  }
//将有效区域单元格转化赋值为 object[,]	
cells=(object[,])worksheet.Range[worksheet.Cells[startrow,_startcell.Column],worksheet.Cells[_lastcell.Row,_lastcell.Column]].Value2;//遍历数组,添加行数据到 DataTable里
int _rowcount=cells.GetLength(0);
int _colcount=cells.GetLength(1);
for(int i=0;i<_rowcount;i++)
{object[] newrowdata=new object[_colcount];for(int j=0;j<_colcount;j++){newrowdata[j]=cells[i,j];}DataRow dr=dt.Rows.Add(newrowdata);
}

删除虚拟列 

重新计算最后单元格,删除 DataSet 最后列(虚拟列),这样就达到正确输出数据集数据的目的。 代码如下:

_lastcell = excel.Cells[_lastcell.Row, _lastcell.Column - 1];
dt.Columns.Remove(dt.Columns[dt.Columns.Count - 1]);

总结

在实际的应用中,还可能遇到更多的合并情况,我们要进行进一步的情况判断和功能完善,让导入功能变得更强大,本文示例提供了一些操作Excel相关的关键方法和属性,这里仅作参考,欢迎大家评论指教!

相关文章:

C# 实现完善 Excel 不规则合并单元格数据导入

目录 功能完善 Excel与DataSet的映射关系 运行环境 Excel DCOM 配置 设计实现 组件库引入 方法更新 返回值 参数设计 打开数据源并计算Sheets 拆分合并的单元格 创建DataTable 将单元格数据写入DataTable 删除虚拟列 总结 功能完善 在我的文章 《C#实现Excel…...

C#功能测试

List 内部元素为引用 src[0]为"11" List<Source> src new List<Source>(); src.Add(new Source() { Name "1", Age 1, Description "1" }); src.Add(new Source() { Name "2", Age 2, Description "2"…...

C++17并行化加速STL算法——std::execution

C17 并行化STL算法 文章目录 C17 并行化STL算法概念环境准备工具类 并行算法 - 使用并行算法 - 执行策略总览选择标准详细介绍顺序执行 seq并行化顺序执行 par并行化乱序执行 par_unseq 并行算法 - 异常处理可以不使用并行算法并行算法 - 限制并行算法有哪些原有算法17引入新算…...

从sumsub获取用户图片

已经拿到了imageid 然后从哪个接口可以获取图片文件呢&#xff1f; 根据您的问题,我可以为您提供以下信息: 一旦您获得了imageId,您可以使用以下几个API接口来获取图片文件: 获取文档图片: Get document images GET https://api.sumsub.com/resources/inspections/{inspection…...

DeepSeek + Mermaid编辑器——常规绘图

下面这张图出自&#xff1a;由清华大学出品的 《DeepSeek&#xff1a;从入门到精通》。 作为纯文本生成模型&#xff0c;DeepSeek虽不具备多媒体内容生成接口&#xff0c;但其开放式架构允许通过API接口与图像合成引擎、数据可视化工具等第三方系统进行协同工作&#xff0c;最终…...

ARM64 Trust Firmware [五 ]

本章介绍 ATF 中的 Runtime Service 是如何定义和被调用的。 要了解 SMC&#xff0c;必须从 SMC 指令本身开始&#xff0c;其指令如下图&#xff1a; 指令格式为&#xff1a;SMC #<imm>&#xff0c;从官方文档了解到该指令只能在 EL1 以及更高的异常等级上调用&#xff…...

Excel核心函数VLOOKUP全解析:从入门到精通

一、函数概述 VLOOKUP是Excel中最重要且使用频率最高的查找函数之一&#xff0c;全称为Vertical Lookup&#xff08;垂直查找&#xff09;。该函数主要用于在数据表的首列查找特定值&#xff0c;并返回该行中指定列的对应值。根据微软官方统计&#xff0c;超过80%的Excel用户在…...

KTransformers如何通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度?

KTransformers通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度&#xff0c;具体体现在以下几个方面&#xff1a; 内核级优化&#xff1a; KTransformers采用了高效的内核级优化技术&#xff0c;包括对Transformer模型中的关键操作进行优化。例如…...

审计级别未启用扩展模式导致查询 DBA_AUDIT_TRAIL 时 SQL_TEXT 列为空

如果查询 DBA_AUDIT_TRAIL 时发现 SQL_TEXT 列为空&#xff0c;但其他字段&#xff08;如 OS_USERNAME、USERNAME、TIMESTAMP 等&#xff09;有数据&#xff0c;可能是由于以下原因之一。以下是可能的原因及解决方法&#xff1a; 1. 审计级别未启用扩展模式 默认情况下&#x…...

微信小程序项目 video 组件失效问题,无法播放本地视频

问题与处理策略 问题描述 <video src"../../assets/video/test-video.mp4" controls style"width: 100%; height: 300px;"></video>在微信小程序项目中&#xff0c;上述 video 组件失效&#xff0c;视频无法加载&#xff0c;无法播放本地视频…...

若依-@Excel新增注解numberFormat

Excel注解中原本的scale会四舍五入小数&#xff0c;导致进度丢失 想要的效果 显示的时候保留两个小数真正的数值是保留之前的数值 还原过程 若以中有一個專門的工具类&#xff0c;用来处理excel的 找到EXCEL导出方法exportExcel()找到writeSheet,写表格的方法找到填充数据的方法…...

网络安全行业有哪些公司

只是简单做一下网络安全公司梳理&#xff0c;不作点评&#xff0c;下列排名不分先后。 一、常见的网络安全公司 1、天融信 天融信&#xff08;002212.SZ&#xff09;创始于1995年&#xff0c;是上市公司中成立最早的网络安全企业&#xff0c;亲历中国网络安全产业的发展历程…...

存储区域网络(SAN)管理

存储区域网络&#xff08;Storage Area Network&#xff0c;SAN&#xff09;采用网状通道&#xff08;Fibre Channel &#xff0c;简称FC&#xff09;技术&#xff0c;通过FC交换机连接存储阵列和服务器主机&#xff0c;建立专用于数据存储的区域网络。SAN提供了一种与现有LAN连…...

如何使用Spark SQL进行复杂的数据查询和分析

使用Spark SQL进行复杂的数据查询和分析是一个涉及多个步骤和技术的过程。以下是如何使用Spark SQL进行复杂数据查询和分析的详细指南&#xff1a; 一、准备阶段 环境搭建&#xff1a; 确保已经安装并配置好了Apache Spark环境。准备好数据源&#xff0c;可以是CSV文件、JSON…...

sass报错:[sass] Undefined variable. @import升级@use语法注意事项

今天创建vue3项目&#xff0c;迁移老项目代码&#xff0c;使用sass的时候发现import语法已经废弃&#xff0c;官方推荐使用use替换。 这里我踩了一个坑找半天的问题&#xff0c;原因是sass升级到1.85之后 定义变量前加上 - 就是表示变量私有&#xff0c;即使使用use导出 在新的…...

使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)安装适配 Java 8 的 Maven

文章目录 1、安装 SDKMAN!2、安装 Maven:2.1、maven 3.9.62.2、maven 3.8.1 好的&#xff0c;这是使用 SDKMAN! 安装适配 Java 8 的 Maven 的步骤&#xff1a; 1、安装 SDKMAN! 前提条件: 安装 SDKMAN!: 如果你的系统上没有安装 SDKMAN!&#xff0c;请按照以下说明进行安装: c…...

anythingllm服务器部署+ollama+deepseek+实现本地知识库问答

一、docker安装anythingllm 1、拉取镜像 docker pull mintplexlabs/anythingllm:latest 2、创建db目录和配置文件并运行 anythingLLM 容器 export STORAGE_LOCATION/data/ai/wjh_team/anythingllm && \mkdir -p $STORAGE_LOCATION && \touch "$STORAG…...

深度学习04 数据增强、调整学习率

目录 数据增强 常用的数据增强方法 调整学习率 学习率 调整学习率 ​调整学习率的方法 有序调整 等间隔调整 多间隔调整 指数衰减 余弦退火 ​自适应调整 自定义调整 数据增强 数据增强是通过对训练数据进行各种变换&#xff08;如旋转、翻转、裁剪等&#xff09;&am…...

2023年全国职业院校技能大赛GZ073网络系统管理赛项赛题第10套模块A:网络构建

​有问题请留言或主页私信咨询 2023年全国职业院校技能大赛 GZ073网络系统管理赛项 赛题第10套 模块A&#xff1a;网络构建 ​ ​ **目 **录 任务清单 &#xff08;一&#xff09;基础配置 &#xff08;二&#xff09;有线网络配置 &#xff08;三&#xff09;无线…...

2023年河北省职业院校技能大赛网络系统管理赛项样题解法

​ 有问题请留言或主页私信咨询 配置文件有部分测试时的冗余配置无视即可。 解法只有大致解法&#xff0c;并不完整。请参考配置&#xff0c;自己补全 基础配置 1.所有交换机和无线控制器开启SSH服务&#xff0c;用户名密码分别为admin、admin1234&#xff1b;密码为明文类…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

​​企业大模型服务合规指南:深度解析备案与登记制度​​

伴随AI技术的爆炸式发展&#xff0c;尤其是大模型&#xff08;LLM&#xff09;在各行各业的深度应用和整合&#xff0c;企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者&#xff0c;还是积极拥抱AI转型的传统企业&#xff0c;在面向公众…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...