学习之路一:关于使用微软的COM组建操作Excel的那些事
前一阵子心血来潮,研究了一下微软的Excel的COM组件,也就是项目中经常需要的导入和导出Excel的案例
本人使用的是微软的Excel COM组件,可能大家都认为使用COM组件性能会变的很差,但这只是记录学习的过程,欢迎拍砖!
好了,废话不说了,直奔主题,Let's go!
1.添加引用步骤
引用操作Excel的DLL有两种选择
①.NET中的DLL
②COM组件的选择
Note:这边会出现版本的问题,随意选择一个就好了!
★ 大家注意了,.NET 和COM里面的引用不要全部选择,不然在编码的过程中会出现引用冲突,切忌!
2.导入Excel
上面的引用加好后,那么在Using的时候就会有如下的效果:
上面的第一种是:using Microsoft.Office.Interop.Excel
第二种是:using Excel
开始操作了,不过接下来讲的一些术语可能不是很准确,不过大概就是那意思!
接下来我使用的都是第二种引用!
① 首先要创建Excel一系列的对象
A) 创建Excel应用对象
1 Excel.Application excelApplication = new Excel.Application();
2
3 object missing = Missing.Value;
4
5 //注意上面这句话,后面的代码中用到的missing就是在这边定义的,通俗的讲这个变量相当于一个二进制值
B) 创建Excel中Workbook工作簿对象
1 //①第一种写法,通过Excel引用对象来指定工作簿对象
2 Workbooks workBooks = excelApplication.Workbooks;
3
4 //通过excelApplication对象创建工作簿对象
5
6 Workbook workBook = workBooks.Add(XlWBATemplate.xlWBATWorksheet); //这边要加个模版类型枚举
7
8 //如果需要自己定义一个模版,可以指定它的路径,如下:
9
10 //string path = @"C:\Documents and Settings\Administrator\桌面\EXCEL测试模板ã.xls";
11
12 //Workbook workBook = workBooks.Add(path);
--------------------------------------------------------------
//②第二种写法
//★:在创建工作簿对象时还有另外一种写法
3 Workbook workBookOne = excelApplication.Workbooks.Open(templetFile,issing, missing, missing, missing, missing,missing,missing, missing, missing, missing, missing, missing);
5 //也可以这样写:
7 Workbook workBookOne = excelApplication.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);
------------------------------------------------------------------------
Note:在上面的Add和Open方法中的第一个参数其实是一个模版的指定,你可以写模版的路径,如果没有模版可以通过XlWBATemplate.xlWBATWorksheet指定默认的模版!
模版的作用其实就是固定你Excel顶部的一些样式,这个也可以通过在Excel中自己指定!
C) 创建Workbook工作簿中的Sheet对象
1 //创建Sheet对象
2
3 Sheets sheets = workBook.Worksheets;
4
5 //创建Sheet工作对象
6
7 //后面的get_Item(1),是获取Excel中第几个Sheet对象
8
9 //Note:这边Sheet的数量是根据你模版中Sheet的数量而定的,不使用模版默认的Sheet数量为“1” ,如果你强制使用“2”或“3”的Sheet就会出现“Sheet索引值无效”的异常信息
10
11 Worksheet workSheet = (Worksheet)sheets.get_Item(1);
12
13 //下面的代码效果跟上面一样
14
15 //_Worksheet workSheetOne = (_Worksheet)sheets.get_Item(2);
16
17 //Note:这边的带有“_”的Worksheet跟上面的没有下划线效果是一样的,所以在操作Excel时,带有下划线和没有的都属于同种类型,使用效果是一样的!
18
19 //-----------------------------------------------------------
20
21 //★ :还有一种写法:
22
23 //也可以这样,那么就可以把上面两句话合为一句了
24 //Worksheet workSheetOne = Excel.Worksheet)workBook.Sheets.get_Item(1);
Note:一开始在创建Sheet对象时,总想着是不是可以多创建几个,试了好多遍,没效果,一直报错,但是当我在指定的模版中定义了几个Sheet后,结果在操作Excel的时候就可以用了!
D) 一切对象准备之后就是数据的填充了
现在为止我填充数据的方式有两个:
① 循环数据,然后使用遍历单元格来填充数据
2 DataSet ds = GetData(); //获取数据源
3 int rowsNumber = ds.Tables[0].Rows.Count; //确定行数
4 int columnNumber = ds.Tables[0].Columns.Count; //列数
5
6 //设置sheet名称
7 workSheet.Name = "Sheet1";
8 //这边是如果模版的Sheet数量为三的时候可以这样指定的,只有当指定的模版中有三个Sheet时,才可以指定!
9 //workSheetOne.Name = "Sheet2";
10 //workSheetTwo.Name = "Sheet3";
11
12 //设置标题
13 for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
14 {
15 workSheet.Cells[1, i + 1] = ds.Tables[0].Columns[i].ColumnName;
16 //Note:这边网上的教程都没有加(object)进行转化,但是我不加就出现错误,所以当这边出现错误时,就加一个(object)的强制转换!
17 //注意这边在填充数据的时候你要指定Cell中的两个参数,第一个是行,第二个是列,当标题设置好了后,那你在添加数据的时候行和列的值都应该“+1”
18 Microsoft.Office.Interop.Excel.Range rang = workSheet.get_Range((object)workSheet.Cells[1, i + 1], (object)workSheet.Cells[1, i + 1]);
19 //设置单元格中的数据水平居中
20 rang.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;
21 //这边使用了Microsoft.Office.Interop.Excel的命名空间,跟上面可能搞混了,这是我一开始经常犯得错误!
22 }
23 //填充数据
24 for (int i = 0; i < rowsNumber; i++)
25 {
26 for (int j = 0; j < columnNumber; j++)
27 {
28 workSheet.Cells[i + 2, j + 1] = ds.Tables[0].Rows[i][j];
29 workSheet.Columns.AutoFit();
30 workSheet.get_Range((object)workSheet.Cells[i + 2, j + 1], (object)workSheet.Cells[i + 2, j + 1]).HorizontalAlignment
31 = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;
32 //设置字体的颜色
33 workSheet.get_Range((object)workSheet.Cells[i + 2, j + 1], (object)workSheet.Cells[i + 2, j + 1]).Font.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);
34 }
35 }
Note:如果在这句话 Microsoft.Office.Interop.Excel.Range rang = workSheet.get_Range((object)workSheet.Cells[1, i + 1], (object)workSheet.Cells[1, i + 1]); 出现了错误,请使用object进行强制转化!
总结:设置表格样式和填充数据的时候都会用到“Worksheet”对象中的get_Range的方法,这个方法很重要,其中里面的两个参数的意思为:第一个为起始单元格的位置,第二个是 以终止的单元格的位置,For example :你设置字体颜色,如果你的两个参数都是为“workSheet.Cells[2, 1]”“ workSheet.Cells[2, 1]”那么说明是只有这个单元格设置字体颜色,在文章的最后面我贴出一些表格样式表!
② 使用二位数组进行批量添加
1 int rowsCount = table.Rows.Count; //行数
2 int columnCount = table.Columns.Count; //列数
3
4 //创建一个二维数组
5 //当你的数据中有数字和字符串的时候尽量是分开进行导入,因为我试过如果都用string方式的导入,会在Excel中出现如下的样式,我感觉就是int和string类型的转化问题!
6
7 string[,] array = new string[rowsCount, columnCount];
8 for (int i = 0; i < rowsCount; i++)
9 {
10 for (int j = 0; j < columnCount; j++)
11 {
12 //赋值=
13 array[i, j] = table.Rows[i][j].ToString();
14 }
15 }
16
17 //⑤
18 workSheet.Name = "Yang Cao Gui";
19 //指定你Excel填充数据开始的位置
20 Range range = (Excel.Range)workSheet.Cells[1, 1];
21 //指定结束的位置,如果开始的位置为Cell[2,2],那么就要加上行和列都要加上1
22 //如:range.get_Resize(rowsCount+1, columnCount+1)
23 range = range.get_Resize(rowsCount, columnCount);
24 range.Value = array;
总结:使用二维数组进行数据添加比较简便,代码很简洁!
E) 保存Excel
保存代码比较简单
1 //保存
2 string homePath = @"C:\Documents and Settings\Administrator\桌面\yang.xls";
3 workBook.SaveAs(homePath, missing, missing, missing, missing, missing, XlSaveAsAccessMode.xlNoChange,missing, missing, missing, missing, missing);
Note:注意SaveAs的一些参数设置,就是前面定义的missing变量!
F)最后清除所有Excel进程
Note:一开始当创建Excel进程时到保存结束后,Excel进程都会存在,不会消失,所以我们在最后应该手动清除它们!,不过当多个用户同时操作时,就会发生并发错误,也就是说我们导出Excel后杀掉进程而其它用户正在导出,那么其它用户就会导出失败的情况!
1 //释放进程
2 //主要有三个参数Excel应用进程,Workbook工作簿进程,Worksheet工作表进程
3 //不过就只有Excel应用进程使用了,其它的两个好像没有作用!
4 public void DisposeExcel(Excel.Worksheet workSheet, Excel.Workbook workBook, Excel.Application excelApp)
5 {
6 try
7 {
8 excelApp.Quit();
9 GC.Collect(); //强制进行GC垃圾回收
10 }
11 catch (Exception ex)
12 {
13 //Response.Write(ex.Message);
14 }
15 finally
16 {
17 //杀掉Excel全部进程,说实话不是最好的解决办法,但是我想我会努力找到办法解决它,这步很重要对于使用微软的DLL!
18 foreach (Process process in Process.GetProcessesByName("Excel"))
19 {
20 process.Kill();
21 }
22 }
3.导出Excel表
Note:主要的原理就是把Excel看做为OLEDB数据,对它进行连接,查询等处理,不过这里面应该要注意很多细节,下面就来一一细看:
① 连接数据库
1 //使用命名空间 using System.Data.OleDb
2 // filePathOne为你Excel表的路径,注意一些关键术语,Provider要注意它的单词拼写!
3 string conn = " Provider = Microsoft.Jet.OLEDB.4.0;Data Source =" + filePathOne + ";Extended Properties=Excel 8.0";
4 OleDbConnection objcon = new OleDbConnection(conn);
5 objcon.Open();
Note:filePathOne → 指的是你Excel的路径!
Note:如果Excel的版本是2007以上的,需要更换连接字符串,切忌,如下:
1 "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+ path +";Extended Properties=Excel 12.0;";
② 确定Excel中Sheet的架构信息
下面就是重点,花了好长时间才搞定的
一开始是按照网上写的,总是出现“数据库搜索引擎未找到对象,请确认拼写是否正确”这样的错误,真烦人!
1 // System.Data.DataTable dt =objcon.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,null);
2 //一开始是这样写,总是报上面的错误,两天时间一直被这个问题困扰着,最后通过MSDN上面的一个列子给解决了!
3 //正确代码:
4 //首要建立一个object数组,这有可能是个规定
5 object[] my = { null, null, null, "TABLE" }; //这句话必须要写,大家如果有其它方案可以告诉我。
6 System.Data.DataTable dt = objcon.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,my);
Note:大家有必要通过GridView来查看上面Table中的信息,一看就会知道其中的奥妙了!
③查找数据
1 //这是指定我要查询的Excel中Sheet的名称
2 //这个很重要,只有正确指定了才能查询数据
3 string name = dt.Rows[0][2].ToString().Trim();
4 //注意加中括号 → “[]”
5 string Sql = "select * from [" + name + "]";
6 OleDbDataAdapter mycommand = new OleDbDataAdapter(Sql, objcon);
7 DataSet ds = new DataSet();
8 mycommand.Fill(ds);
9 objcon.Close();
Note:上面变量name就是获取你指定的Excel中的Sheet名称,因为它的名称在表中的位置是固定,所以可以直接查出来!
最后Excel表中的数据就全部保存到Table中了!
④全部代码
1 public System.Data.DataTable UploadExcel(string filePath)
2 {
3 string filePathOne = @"C:\Documents and Settings\Administrator\桌面\TnT_UserMaintenance_Test-Specifications.xls";
4 string conn = " Provider = Microsoft.Jet.OLEDB.4.0;Data Source =" + filePathOne + ";Extended Properties=Excel 8.0";
5 OleDbConnection objcon = new OleDbConnection(conn);
6 objcon.Open();
7 object[] my = { null, null, null, "TABLE" };
8 System.Data.DataTable dt = objcon.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, my);
9 string name = dt.Rows[0][2].ToString().Trim();
10 string Sql = "select * from [" + name + "]";
11 OleDbDataAdapter mycommand = new OleDbDataAdapter(Sql, objcon);
12 DataSet ds = new DataSet();
13 mycommand.Fill(ds);
14 objcon.Close();
15 return ds.Tables[0];
16 }
总结:这种导入Excel的方法比较简单,如果自己手打我相信遇到的问题还真是不少,其中你要对System.Data.DataTable dt = objcon.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, my); 中架构信息的理解,你可以使用GridView来查看架构信息,那么对于理解是很方便的!如下图:
这样你就能很好的把握Sheet中的表名,其实都是有规律的,基本都可以通过dt.Rows[0][2]这样来读取,因为Sheet名都是在第三列中,也就是索引的“2”,唯一变的就是行数索引的变化,这主要是针对有多个Sheet的时候才有的情况,基本都是dt.Rows[0][2]来读取第一个Sheet名称!
当然当你想导入的Excel中有多个Sheet对象时,这时查看架构信息是很有帮助的,以免出错!
3.一些对表格样式操作的方法
没有深入研究,想深入了解可以网上找找
1 1、 显示当前窗口:ExcelApp.Visible := True;
2 2、 更改 Excel 标题栏:ExcelApp.Caption := '标题内容';
3 3、 添加新工作簿:ExcelApp.WorkBooks.Add;
4 4、 设置第2个工作表为活动工作表:ExcelApp.WorkSheets[2].Activate;
5 5、 给单元格赋值:ExcelApp.Cells[1,1].Value := '第一行第一列';
6 6、 设置指定列的宽度(单位:字符个数),以第一列为例:
7 ExcelApp.ActiveSheet.Columns[1].ColumnsWidth := 5;
8 7、 设置指定行的高度(单位:磅)(1磅=0.035厘米),以第二行为例:
9 ExcelApp.ActiveSheet.Rows[2].RowHeight := 1/0.035; // 1厘米
10 8、文字水平居中:Excelid.worksheets[1].Rows[1].HorizontalAlignment := $FFFFEFF4;
11 文字垂直居中:Excelid.worksheets[1].Rows[1].VerticalAlignment := $FFFFEFF4;
12 9、 插入一行或一列:a. ExcelApp.ActiveSheet.Rows[2].Insert;
13 b. ExcelApp.ActiveSheet.Columns[1].Insert;
14 10、 删除一行或一列:a. ExcelApp.ActiveSheet.Rows[2].Delete;
15 b. ExcelApp.ActiveSheet.Columns[1].Delete;
16 11、合并单元格:ExcelApp.worksheets[1].range[A1:F8'].Merge(abc);注:要声明变量abc: Variant;
17 12、竖行显示文字:ExcelApp.worksheets[1].Cells.Item[1,1].Orientation:= xlVertical;
18 13、单元格加边线:ExcelApp.worksheets[1].Range[A1:F8].Borders.LineStyle := 1;
19 14、在第8行之前插入分页符:ExcelApp.WorkSheets[1].Rows[8].PageBreak := 1;
20 15、在第4列之前删除分页符:ExcelApp.ActiveSheet.Columns[4].PageBreak := 0;
21 16、指定边框线宽度:ExcelApp.ActiveSheet.Range[ 'B3:D4' ].Borders[2].Weight := 3;
22 1-左 2-右 3-顶 4-底 5-斜( \ ) 6-斜( / )
23 17、拷贝操作:a.拷贝整个工作表:ExcelApplication1.ActiveSheet.Used.Range.Copy;
24 b.拷贝指定区域:ExcelApplication1.ActiveSheet.Range[ 'A1:E2' ].Copy;
25 c.从A1位置开始粘贴:ExcelApplication1.ActiveSheet.Range.[ 'A1' ].PasteSpecial;
26 d.从文件尾部开始粘贴:ExcelApplication1.ActiveSheet.Range.PasteSpecial;
27 18、清除第一行第四列单元格公式:ExcelApp.ActiveSheet.Cells[1,4].ClearContents;
28 19、工作表保存:if not ExcelApp.ActiveWorkBook.Saved then
29 ExcelApp.ActiveSheet.PrintPreview;
30 20、工作表另存为:ExcelApp.SaveAs( 'C:\Excel\Demo1.xls' );
31 21、放弃存盘:ExcelApp.ActiveWorkBook.Saved := True;
32 22、关闭工作簿:ExcelApp.WorkBooks.Close;
33 23、退出 Excel:ExcelApp.Quit;
34 下面是有关打印页面控制的语句:
35 24、设置第一行字体属性:ExcelApp.ActiveSheet.Rows[1].Font.Name := '隶书';
36 ExcelApp.ActiveSheet.Rows[1].Font.Color := clBlue;
37 ExcelApp.ActiveSheet.Rows[1].Font.Bold := True;
38 ExcelApp.ActiveSheet.Rows[1].Font.UnderLine := True;
39 ExcelApp.ActiveSheet.Rows[1].Font.size:=10;
40 25、进行页面设置:a.页眉:ExcelApp.ActiveSheet.PageSetup.CenterHeader := '报表演示';
41 b.页脚:ExcelApp.ActiveSheet.PageSetup.CenterFooter := '共&N页 第&P页';
42 c.页眉到顶端边距2cm:ExcelApp.ActiveSheet.PageSetup.HeaderMargin := 2/0.035;
43 d.页脚到底端边距3cm:ExcelApp.ActiveSheet.PageSetup.HeaderMargin := 3/0.035;
44 e.顶边距2cm:ExcelApp.ActiveSheet.PageSetup.TopMargin := 2/0.035;
45 f.底边距2cm:ExcelApp.ActiveSheet.PageSetup.BottomMargin := 2/0.035;
46 g.左边距2cm:ExcelApp.ActiveSheet.PageSetup.LeftMargin := 2/0.035;
47 h.右边距2cm:ExcelApp.ActiveSheet.PageSetup.RightMargin := 2/0.035;
48 i.页面水平居中:ExcelApp.ActiveSheet.PageSetup.CenterHorizontally := 2/0.035;
49 j.页面垂直居中:ExcelApp.ActiveSheet.PageSetup.CenterVertically := 2/0.035;
50 k.打印单元格网线:ExcelApp.ActiveSheet.PageSetup.PrintGridLines := True;
51 26、打印预览工作表:ExcelApp.ActiveSheet.PrintPreview;
52 27、打印输出工作表:ExcelApp.ActiveSheet.PrintOut;
53 对Excel的其他控制:
54 28、excel的多单元格合计功能:ExcelApp..Cells[ARow, ACol].Formula
55 := '= SUM($+IntToStr(BeginRow) +:$ + IntToStr(EndRow) +');
56 注:声明变量ARow, ACol: Integer;
57 29、打开已经存在的Excel文件: ExcelApplication1.Workbooks.Open (c:\a.xls
58 EmptyParam,EmptyParam,EmptyParam,EmptyParam,
59 EmptyParam,EmptyParam,EmptyParam,EmptyParam,
60 EmptyParam,EmptyParam,EmptyParam,EmptyParam,0);
好了,基本的Excel操作就这么多了,可能现在很多人都使用那些非常好用的Excel类库,但是了解这个个人觉得还是有必要的!
其实讲的这些只是一个很基础的,对于表格样式,多个人同时导出Excel表的时候的并发情况等等,这个就需要我们不断的探索和学习!
下一篇:关于集合和数组的内在联系