ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: excelhomesnake

[分享] vsto中,处理excel数据的基本套路(C#)

[复制链接]

TA的精华主题

TA的得分主题

发表于 2015-12-18 17:20 | 显示全部楼层
excelhomesnake 发表于 2015-12-18 16:33
要的,这个sdk是另外的,不是.net 系统自带的.上网找一下连接,到微软官网就有下载的

好的,我找找!

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-12-21 13:18 | 显示全部楼层
接着之前说的.这里具体说说代码部分.
需求与之前的一样,从<数据源>中,查找第二列的内容中,开头是"普通",的行,复制到<结果输出>的工作表中
要在项目中引用

  • DocumentFormat.OpenXml



  • WindowsBase



  • 打开excel文档.
  • 如果需要保存文档的修改内容,第二个参数要设置为true

  1. <P>using (SpreadsheetDocument doc = SpreadsheetDocument.Open(path, false))
  2. {</P>
  3. <P>        //操作文档的逻辑</P>
  4. <P>}</P>
复制代码

获取指定工作表的对象:

  • 正如之前所说,工作表的名字信息,是在Workbook对象下的Sheets才有.这里关键是需要获取我们需要的工作表的id
  • Descendants方法,可以直达到某个指定类型的节点.这里的意思就是,获取Workbook下所有类型是Sheet的节点.然后使用linq的一个方法First,获取的一个符合条件的对象出来
  • 然后通过WorkbookPart的方法GetPartById(),就可以获取我们要的工作表的WorksheetPart.
  • GetPartById方法是OpenXmlElement对象的方法.很多对象都是他的子类.因此这些子类都有这个方法来获取下一层的part对象.但也是这个原因,这个方法的返回值是OpenXmlElement对象,因此需要显示转换才可以.
  1. WorkbookPart wbPart = doc.WorkbookPart;
  2. Sheet query_ws = wbPart.Workbook.Descendants<Sheet>().First(ws => ws.Name == "数据源");

  3. WorksheetPart wsPart = (WorksheetPart) wbPart.GetPartById(query_ws.Id);
复制代码


清除结果输出工作表的内容:

  • 每个WorksheetPart下,都有SheetData对象来保存单元格数据内容
  • 我发现在Worksheet对象,没有一个属性可以直接获取对应的SheetData对象(很多对象都是这样),这种情况一般使用Descendants方法就可以获取.例如这里可以通过.Descendants<Row>()就可以获取这个工作表下的所有行对象
  • 这里偷懒,就直接用linq方法Skip跳过第一行标题行,然后使用方法Reverse来倒序输出遍历
  1. WorksheetPart outputSheet = (WorksheetPart) wbPart.GetPartById(wbPart.Workbook.Descendants<Sheet>().First(ws => ws.Name == "结果输出").Id);
  2. SheetData outputSheetData=outputSheet.Worksheet.Descendants<SheetData>().ElementAt(0);

  3. //删除行,记得按照常规,要从下往上清除行
  4. foreach (Row tmpRow in outputSheet.Worksheet.Descendants<Row>().Skip(1).Reverse())
  5. {
  6. tmpRow.Remove();
  7. }
复制代码

遍历处理每一行,每个单元格:

  • 通过Row对象的ChildElements方法,可获取Cell对象.由于是继承OpenXmlElement对象的方法,所以要转换.
  • 通过HasChildren判断是否有子元素,因为单元格有可能只有格式,没有值
  • 通过DataType 属性,判断该单元格内容是什么类型.这个关系到我们获取到的值,到底是显示值本身,还是只是一个shareStringTable的索引
  • 然后就是当内容是ShareString的时候,就去ShareTable找.通过ChildElements索引属性就可以找到.

  1. //从第二行开始遍历每一行
  2. for (int irow = 0; irow < rows.Length; irow++)
  3. {
  4. Row tmpRow=rows[irow];


  5. //获取第2列单元格
  6. Cell cell = (Cell) tmpRow.ChildElements[1];

  7. //单元格值是单元格的子元素,在有子元素情况下,才有值
  8. if (cell.HasChildren)
  9. {

  10. //这个单元格的值
  11. string value = cell.CellValue.Text;

  12. //这个单元格的内容,如果是一个excel文本类型,则这个value是一个sharestringtable表的索引.
  13. //如果是文本类型,才有Datatype
  14. if (cell.DataType != null && cell.DataType == CellValues.SharedString)
  15. {

  16. value = ssTable.ChildElements[int.Parse(value)].InnerText;
复制代码

把符合条件的行对象,复制到<结果输出>工作表中.

  • 把符合条件的行对象,复制一个到新的行对象
  • 记得要修改行索引和里面的Cell对象的地址
  • 最后通过Append方法,把新的行对象添加到SheetData对象中

  1. //写入
  2. Row inputRow = (Row) tmpRow.Clone();

  3. inputRow.RowIndex = inputRowIndex;

  4. //修改cell的地址
  5. foreach (Cell tmpCell in inputRow)
  6. {


  7. tmpCell.CellReference.Value = tmpCell.CellReference.Value.Remove(1) + inputRowIndex.ToString();


  8. }




  9. outputSheetData.Append(inputRow);
复制代码


注意:

  • 其实在打开文档之前,需要先判断该文件是否被占用.如果被占用,会抛出一个IO异常.
  • 可以看出,使用openxml库,真的是很麻烦.如果自己不封装一下,真的难以长期使用.

分享帖(3).rar

176.05 KB, 下载次数: 57

TA的精华主题

TA的得分主题

发表于 2015-12-21 15:08 | 显示全部楼层
excelhomesnake 发表于 2015-12-21 13:18
接着之前说的.这里具体说说代码部分.
需求与之前的一样,从中,查找第二列的内容中,开头是"普通",的行,复制 ...

Mark先,有空细看。

TA的精华主题

TA的得分主题

发表于 2017-5-25 19:35 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
Mark一下~~

TA的精华主题

TA的得分主题

发表于 2017-8-22 22:28 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2017-10-29 23:03 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
excelhomesnake 发表于 2015-12-17 16:55
2,如何通过封装,达到通用处理二维数组的处理.(例如,各种排序,汇总等操作)

prod_2过程:已经把二维数组封 ...

转为datatable处理也很方便

TA的精华主题

TA的得分主题

发表于 2017-12-27 14:53 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2018-1-16 14:34 | 显示全部楼层
先下载,回头学习一下,谢谢楼主

TA的精华主题

TA的得分主题

发表于 2018-2-23 18:02 | 显示全部楼层
获取excel的工作线程以后可以做什么?

TA的精华主题

TA的得分主题

发表于 2020-4-8 14:51 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-21 20:19 , Processed in 0.040470 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表