经常会有项目需要把表格导出为 Excel 文件,或者是导入一份 Excel 来操作,那么如何在 C# 中操作 Excel 文件成了一个最基本的问题。

做开发这几年来,陆陆续续也接触过这样的需求,但因为不频繁,所以经常是遇到问题再去网上搜。最近的一个项目,要导出的这个 Excel 涉及了很多比较偏僻的操作,所以决定在这里开一篇文章,专门用来收集和整理使用到的代码,以及一些技巧。如果各位看官有一些自己的心得,或者有更好的方案,也欢迎交流。我会时不时更新一下。

0. 使用之前

在写代码之前,我们需要先添加引用,在 程序集 – 扩展 里面:Microsoft.Office.Interop.Excel。
还有要注意的是,引用之后,需要将属性中的「嵌入互操作类型」设置为 Flase,不然编译时可能会出错。
然后就是记得 using 啦:

using Microsoft.Office.Interop.Excel;
using System.Reflection;

▲ 这里的第二个 using 是因为在 Excel 操作中会经常用到一个 Missing.Value 的默认值,所以需要先引用 System.Reflection。

1. 开始使用

一般在使用中,我们只是操作一份 Excel 中的第一个工作表(sheet),下面来最简单的创建和读取一份 Excel 中的第一个 sheet。

// 定义一个 Missing 的值,方便后面使用
Missing miss = Missing.Value; // 创建 Excel,并制定是不可见的
ApplicationClass excel = new ApplicationClass();
excel.Visible = false; // 新建一份电子表格,或者打开现有的文件
Workbook wb = excel.Workbooks.Add();
Workbook wb = excel.Workbooks.Open("demo.xls"); // 取得到第一个工作表,或者取得当前默认的工作表
Worksheet ws = wb.Sheets[] as Worksheet;
Worksheet ws = wb.ActiveSheet as Worksheet;

▲ 注意,在 Excel 的操作中,许多时候,索引是从 1 开始的,而不是 0,这和大多数程序语法有区别。

2. 使用之后

既然已经把 Excel 都创建出来了,我们就先来说说使用之后的结束,以及保存文件,需要注意的问题。这就好比在写代码,两个花括号都是同时敲的,过后再来写里面的代码。

许多资料中,Excel 使用之后都直接就 excel = null; 来结束代码,这些朋友难道没发现,这样会在系统中留下许多 EXCEL.EXE 的进程吗?如下图:

如果这是在用户的客户端,可能会因为关机,而把这个问题忽略。但如果是在服务器上生成 Excel 文件,一个用户生成一次,就产生一个进程,那么后果可想而知。所以我们要来先说说使用之后怎么结束 Excel 的进程。
结束 Excel 不能单单把 EXCEL.EXE 结束就好,这样的话,如果用户正好打开了一个 Excel 也会被结束掉。
下面是正确结束 Excel 的代码:

[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID); // 结束 Excel 进程
public static void KillExcel(Application excel)
{
IntPtr t = new IntPtr(excel.Hwnd);
int k = ;
GetWindowThreadProcessId(t, out k);
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k);
p.Kill();
}

▲ 注意 DllImport 需要 using System.Runtime.InteropServices 。

接下来就是比较保险的关闭,以及调用上面的代码:

// 关闭电子表格,释放资源
wb.Close();
wb = null; // 退出 Excel,释放资源
excel.Quit();
KillExcel(excel);
excel = null;

3. 保存时的格式问题

「文件格式和扩展名不匹配。文件可能已损坏或不安全。」看起来似乎很严重,尤其对一些电脑小白来说,不安全这个词很耀眼。这个问题,可能很多朋友在做 Excel 导出的时候,都会遇到,包括我自己使用一些软件也遇过,绝大多数都没有对这个问题进行处理,觉得让用户点一下「是」就好了。但对于我这种相对注重用户体验的开发者来说,这样当然是不行的。那么到底是什么造成的?
其实解决这个问题非常简单,之所以会出现这个问题,是和 Office Excel 的版本有关系。我们都知道 Excel 有一个 97-2003 的格式,就是最常见的 .xls 文件,除了这个还有一种 .xlsx 文件,这种是自 Office Excel 2007 之后有的新格式,除了这些,Excel 还支持把表格保存为 .xml 甚至是纯文本的格式。而我们用程序在生成 Excel 的时候,考虑到国内还有一大批 Office 2003 的使用者,所以我们都会保存为 .xls 以便更好的兼容他们。大部分都是像下面的代码这个保存的:

// 保存
wb.SaveAs("demo.xls");

虽然你的保存路径中有包含 .xls 后缀名,但其实这个时候,Excel 并不知道你是要以什么格式去保存,所以它可能是无格式的,或者是当前系统中 Office 版本的默认格式。
现在我们来看看 SaveAs 的参数中,会发现还有第二个参数 FileFormat,顾名思义,就是文件格式,正好是我们要的参数,所以我们只要告诉 Excel 要保存的格式,问题迎面而解:

// 保存,格式编码为56(xls)(.xlsx 的编码为51)
wb.SaveAs("demo.xls", );

现在再打开生成的 demo.xls 文件,会发现直接就打开了,不会再出现上面的问题了。

4. 常用的格式设置

在操作 Excel 的时候,除了上面这些基础问题,还有就是一些常见的格式设置。包括字体字号、粗体、合并单元格、垂直居中、横向居中、行高、列宽、单元格格式,边框样式,等等。下面的代码就包含了这些常用的设置:

// 选择一块区域(一个或多个单元格之间)
Range range = ws.get_Range(ws.Cells[, ], ws.Cells[, ]); // 设定单元格格式,@是指文本格式(导出一串长数字时,例如手机号码,会被处理为数字,所以我们要强制为文本)
range.NumberFormat = "@"; // 合并单元格
range.MergeCells = true; // 设置行高、列宽
range.RowHeight = ;
range.ColumnWidth = ; // 设置字体字号、粗体、字体(还有大多数字体相关的都在 Font 属性中)
range.Font.Size = ;
range.Font.Bold = true;
range.Font.Name = "楷体"; // 横向居中、垂直居中
range.HorizontalAlignment = XlHAlign.xlHAlignCenter;
range.VerticalAlignment = XlHAlign.xlHAlignCenter; // 设置边框
range.Borders.LineStyle = ;
range.Borders.LineStyle = XlLineStyle.xlContinuous; // 给单元格设置值(内容)
range.set_Value(miss, "abel.cnblogs.com");

比较麻烦的是,每操作一个区域,我们就要重新设定一次 Range,这相当于在 Excel 实际做了一次选择某些单元格的操作,所以数据量大的话,生成 Excel 的速度会有点慢。

5. 常用的打印设置

这部分可能在网上比较少见,但一些项目中也会有相关的需求,比如要默认横向纸张啦,打印标题行啦(就是不管打印到第几页,都会出现这一行,一般是表格第一行)等等,我们来看看代码吧:

// 设置横向纸张
ws.PageSetup.Orientation = XlPageOrientation.xlLandscape; // 设置打印标题的范围
ws.PageSetup.PrintTitleRows = "$3:$3";

6. 其它设置

还有一些其它的设置和操作,暂时先都整理在这吧。

// 设置电子表格的名称
ws.Name = "Hello C#";

7. 关于生成速度慢的解决方案…

上面我们有提到,使用程序来生成 Excel,遇到数据量大的话(十万级的数据就足够了),会比较慢的问题,这个怎么破?
其实我们可以不使用 Excel 操作类来生成,而是直接用 IO 来生成 xml 格式的 Excel 表格,最后保存为 .xls 文件即可,速度可以提高N倍。当然,会出现上面第三点说的问题。
那有没有速度又快,又不会出现那个安全提示的方法呢?也是有的,来看看代码:

// 打开 XML 格式的 Excel 文件
Workbook wb = excel.Workbooks.OpenXML("temp.xml"); // 再保存为真正 xls 格式的 Excel 文件
wb.SaveAs("demo.xls", );

是的,方法就是先打开一份用 IO 生成好的 xml 格式的 Excel,再另存为 Office 97-2003 格式的 xls 文件。
注意,这个方法只适合格式简单的 Excel,不然在保存的时候,会提示兼容问题!

转-C# 操作 Excel 常见问题收集和整理的更多相关文章

  1. C# 操作 Excel 常见问题收集和整理

    C# 操作 Excel 常见问题收集和整理(定期更新,欢迎交流) 经常会有项目需要把表格导出为 Excel 文件,或者是导入一份 Excel 来操作,那么如何在 C# 中操作 Excel 文件成了一个 ...

  2. C# 操作 Excel 常见问题收集和整理(定期更新,欢迎交流)

    经常会有项目需要把表格导出为 Excel 文件,或者是导入一份 Excel 来操作,那么如何在 C# 中操作 Excel 文件成了一个最基本的问题. 做开发这几年来,陆陆续续也接触过这样的需求,但因为 ...

  3. C#操作Excel开发报表系列整理(转)

    C#操作Excel进行报表开发系列共写了七篇,也已经有很久没有新东西了,现在整理一下,方便以后查阅,如果有写新的,会同时更新.需要注意的是因为Office的版本不同,实际的代码可能会有所不同,但是都是 ...

  4. C#操作Excel开发报表系列整理

    C#操作Excel进行报表开发系列共写了八篇,也已经有很久没有新东西了,现在整理一下,方便以后查阅,如果有写新的,会同时更新.需要注意的是因为Office的版本不同,实际的代码可能会有所不同,但是都是 ...

  5. POI 操作 excel表格 (简单整理)

    简单的整理: import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import ...

  6. C++ builder 操作Excel方法(据网上资料整理)

    c++ builder 操作Excel方法,下面是从网上找到的一些不错的方法,学习一下: 用OLE操作Excel(目前最全的资料)(04.2.19更新) 本文档部分资料来自互联网,大部分是ccrun( ...

  7. VB操作EXCEL文件

    用VB操作Excel(VB6.0)(整理) 首先创建Excel对象,使用ComObj:Dim ExcelID as Excel.ApplicationSet ExcelID as new Excel. ...

  8. NPOI操作EXCEL(一)——npoi基础

    去年项目有一个子模块需要解析上百张不一样的excel表格入库,当时用的NPOI,做了很久...也尝试想把代码分享到oschina,结果没坚持两篇就放弃了. 赶巧的是,昨天运营那边提出要录入一些基础数据 ...

  9. C#操作Excel的技巧与方法 设置单元格等

    C#操作Excel可以分为客户端和插件版本,区别就是是否需要Excel环境,功能实现一样 一.通用操作与处理(有点乱有时间再整理) 1:工程对excel类库的导入,如: c:\program file ...

随机推荐

  1. Qt 静态函数QMetaObject::connectSlotsByName(QObject * object)按命名规则自动connect,不需要手动connect

    看别人代码看到void on_MyWidget_slotTest(); 就郁闷了,没看到他代码里有connect 却能把信号和槽可以连接起来. 今日回顾书本发现该函所的nb之处. QMetaObjec ...

  2. poj2154

    利用bzoj2705的结论我们很容易优化这道等价类计数的问题 sum(n^gcd(i,n))/n mod p (1<=i<=n) =sum(phi(n/L)*n^L)/n mod p (n ...

  3. 安装PyQt

    下载PyQt(版本一定要对) http://www.riverbankcomputing.com/software/pyqt/download import sys,urllib2 from HTML ...

  4. java基础(十九)IO流(二)

    这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...

  5. RHEL7磁盘分区挂载和格式化

    安装大数据平台,每台机器需要挂载10个磁盘,用JBOD模式,操作系统为RHEL7.2. 写了两个脚本,format_disk.sh和mount_disk.sh实现磁盘自动分区格式化以及挂载,修改fst ...

  6. HTML头部<head>学习

    元素是所有头部元素的容器. 元素包含了所有的头部标签元素.在 元素中你可以插入脚本(scripts), 样式文件(CSS),及各种meta信息. 以下标签都可以添加到 head 部分: 1.title ...

  7. svn 被锁定

    遇到svn被锁定,clearup 不管用一直报错 用命令行解决了 问题 : command line -> cmd>svn help>svn cleanup>exit

  8. Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理

    IOC的基础 下面我们从IOC/AOP开始,它们是Spring平台实现的核心部分:虽然,我们一开始大多只是在这个层面上,做一些配置和外部特性的使用工作,但对这两个核心模块工作原理和运作机制的理解,对深 ...

  9. 如何把select出来的一列数据放在第一个单元格

    有如下表: STORE_ID |  CUSTOMER_ID S001       |      C001 S001       |      C002 能不能把上表SELECT出来变成下面这种形式: ...

  10. 用Android++在Visual Studio中用C/C++开发Android应用

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:用Android++在Visual Studio中用C/C++开发Android应用.