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()!="" 来判断是否转化成功。
参数设计
- string _filename:Excel 数据源文件路径
- bool hastitle: 是否包含标题,如果设置为true,则表示首行数据为列名称定义
- string startaddress:可指定有效的起始单元格地址,不设置则默认为“A1”(即第一个单元格)
- 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 然后从哪个接口可以获取图片文件呢? 根据您的问题,我可以为您提供以下信息: 一旦您获得了imageId,您可以使用以下几个API接口来获取图片文件: 获取文档图片: Get document images GET https://api.sumsub.com/resources/inspections/{inspection…...
DeepSeek + Mermaid编辑器——常规绘图
下面这张图出自:由清华大学出品的 《DeepSeek:从入门到精通》。 作为纯文本生成模型,DeepSeek虽不具备多媒体内容生成接口,但其开放式架构允许通过API接口与图像合成引擎、数据可视化工具等第三方系统进行协同工作,最终…...
ARM64 Trust Firmware [五 ]
本章介绍 ATF 中的 Runtime Service 是如何定义和被调用的。 要了解 SMC,必须从 SMC 指令本身开始,其指令如下图: 指令格式为:SMC #<imm>,从官方文档了解到该指令只能在 EL1 以及更高的异常等级上调用ÿ…...
Excel核心函数VLOOKUP全解析:从入门到精通
一、函数概述 VLOOKUP是Excel中最重要且使用频率最高的查找函数之一,全称为Vertical Lookup(垂直查找)。该函数主要用于在数据表的首列查找特定值,并返回该行中指定列的对应值。根据微软官方统计,超过80%的Excel用户在…...
KTransformers如何通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度?
KTransformers通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度,具体体现在以下几个方面: 内核级优化: KTransformers采用了高效的内核级优化技术,包括对Transformer模型中的关键操作进行优化。例如…...
审计级别未启用扩展模式导致查询 DBA_AUDIT_TRAIL 时 SQL_TEXT 列为空
如果查询 DBA_AUDIT_TRAIL 时发现 SQL_TEXT 列为空,但其他字段(如 OS_USERNAME、USERNAME、TIMESTAMP 等)有数据,可能是由于以下原因之一。以下是可能的原因及解决方法: 1. 审计级别未启用扩展模式 默认情况下&#x…...
微信小程序项目 video 组件失效问题,无法播放本地视频
问题与处理策略 问题描述 <video src"../../assets/video/test-video.mp4" controls style"width: 100%; height: 300px;"></video>在微信小程序项目中,上述 video 组件失效,视频无法加载,无法播放本地视频…...
若依-@Excel新增注解numberFormat
Excel注解中原本的scale会四舍五入小数,导致进度丢失 想要的效果 显示的时候保留两个小数真正的数值是保留之前的数值 还原过程 若以中有一個專門的工具类,用来处理excel的 找到EXCEL导出方法exportExcel()找到writeSheet,写表格的方法找到填充数据的方法…...
网络安全行业有哪些公司
只是简单做一下网络安全公司梳理,不作点评,下列排名不分先后。 一、常见的网络安全公司 1、天融信 天融信(002212.SZ)创始于1995年,是上市公司中成立最早的网络安全企业,亲历中国网络安全产业的发展历程…...
存储区域网络(SAN)管理
存储区域网络(Storage Area Network,SAN)采用网状通道(Fibre Channel ,简称FC)技术,通过FC交换机连接存储阵列和服务器主机,建立专用于数据存储的区域网络。SAN提供了一种与现有LAN连…...
如何使用Spark SQL进行复杂的数据查询和分析
使用Spark SQL进行复杂的数据查询和分析是一个涉及多个步骤和技术的过程。以下是如何使用Spark SQL进行复杂数据查询和分析的详细指南: 一、准备阶段 环境搭建: 确保已经安装并配置好了Apache Spark环境。准备好数据源,可以是CSV文件、JSON…...
sass报错:[sass] Undefined variable. @import升级@use语法注意事项
今天创建vue3项目,迁移老项目代码,使用sass的时候发现import语法已经废弃,官方推荐使用use替换。 这里我踩了一个坑找半天的问题,原因是sass升级到1.85之后 定义变量前加上 - 就是表示变量私有,即使使用use导出 在新的…...
使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)安装适配 Java 8 的 Maven
文章目录 1、安装 SDKMAN!2、安装 Maven:2.1、maven 3.9.62.2、maven 3.8.1 好的,这是使用 SDKMAN! 安装适配 Java 8 的 Maven 的步骤: 1、安装 SDKMAN! 前提条件: 安装 SDKMAN!: 如果你的系统上没有安装 SDKMAN!,请按照以下说明进行安装: 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 数据增强、调整学习率
目录 数据增强 常用的数据增强方法 调整学习率 学习率 调整学习率 调整学习率的方法 有序调整 等间隔调整 多间隔调整 指数衰减 余弦退火 自适应调整 自定义调整 数据增强 数据增强是通过对训练数据进行各种变换(如旋转、翻转、裁剪等)&am…...
2023年全国职业院校技能大赛GZ073网络系统管理赛项赛题第10套模块A:网络构建
有问题请留言或主页私信咨询 2023年全国职业院校技能大赛 GZ073网络系统管理赛项 赛题第10套 模块A:网络构建 **目 **录 任务清单 (一)基础配置 (二)有线网络配置 (三)无线…...
2023年河北省职业院校技能大赛网络系统管理赛项样题解法
有问题请留言或主页私信咨询 配置文件有部分测试时的冗余配置无视即可。 解法只有大致解法,并不完整。请参考配置,自己补全 基础配置 1.所有交换机和无线控制器开启SSH服务,用户名密码分别为admin、admin1234;密码为明文类…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
