ASP.NET 中DataTable调用Excel模块直接生成Excel文件的方法
在制作ASP.NET应用程序过程中,有些表需要使用Excel格式导出。一种方式是通过VS自带的水晶报表或者MicrosoftReportViewer组件生成报表后导出,另外一种,就是通过调用Microsoft.Office.Interop.Excel DLL库直接操作。以往的项目中,我总是采用第一种方法,现在我尝试采用第二种方法。
在查阅了相关资料后,在VS2008中导入Microsoft.Office.Interop.Excel 组件包,实现直接对Excel表进行创建和自定义保存。这种方法唯一的遗憾是,由于ASP.NET程序放在服务器端,用户客户端实际上无法直接调用服务器中的Excel组件实现在线Excel文件编辑,除非服务器中的Office支持远程调用,这是另一项技术了。因此,依然采用本地生成Excel文件并提供下载的方式实现Excel导出。
而这种方法的另外一个问题是,在测试中,即便使用Excel组件包中自带的方法退出并释放资源,Excel的进程依然存在,要通过查杀进程的方法最终释放Excel资源。下面的代码参考了园子中周德伦 的Blog资料,对他提供的帮助表示谢意。
参考的相关资料:http://www.cnblogs.com/zhoudelun/articles/1504826.html
首先增加Microsoft.Office.Interop.Excel DLL库引用。我发现有两个版本,但是实际测试下来11不支持xslx文件导出,12支持,我选择高版本。
接下来就是贴代码了,我将整个aspx.cs文件全部贴上来做个记录,通过这种方式,可以实现DataTable直接输出生成Excel 2003或者Excel 2007文件。杀进程的方法参考了网上的其他资料,其实大同小异,有兴趣的童鞋可以自己在网上搜。
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.UI;
6 using System.Web.UI.WebControls;
7 using System.Data;
8 using Microsoft.Office.Interop.Excel; //调用Excel的组件,竟然是NET1.1版本的
9 using System.Runtime.InteropServices; //调用系统进程的组件
10 using System.Diagnostics; //调用DLLImport接口
11
12
13
14
15 namespace DisableQstStatic
16 {
17 public partial class _Default : System.Web.UI.Page
18 {
19
20 //插入进程ID,来自于网络
21 [DllImport("User32.dll", CharSet = CharSet.Auto)]
22 public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
23
24 protected void Page_Load(object sender, EventArgs e)
25 {
26
27
28 DataTable DBStatic = new DataTable();
29 if (DBStatic.Rows.Count > 0 && DBStatic.Columns.Count > 1)
30 {
31 try
32 {
33 Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application(); //调用Excel组件
34 Workbook excelbook = excel.Application.Workbooks.Add(true);//在Excel中添加一个工作簿
35 excel.Visible = false;//设置Excel是否显示
36 //生成字段名称
37 for (int i = 0; i < DBStatic.Columns.Count; i++)
38 {
39 excel.Cells[1, i + 1] = DBStatic.Columns[i].Caption;//将数据表格控件中的列表头填充到Excel中
40 }
41 //填充数据
42 for (int i = 0; i < DBStatic.Rows.Count - 1; i++)//遍历数据表格控件的所有行
43 {
44 for (int j = 0; j < DBStatic.Columns.Count; j++)//遍历数据表格控件的所有列
45 {
46 if (DBStatic.Rows[i][j].GetType() == typeof(string))//判断遍历到的数据是否是字符串类型
47 {
48 excel.Cells[i + 2, j + 1] = "'" + DBStatic.Rows[i][j].ToString();//填充Excel表格
49 }
50 else
51 {
52 excel.Cells[i + 2, j + 1] = DBStatic.Rows[i][j].ToString();//填充Excel表格
53 }
54 }
55 }
56 object missing=System.Reflection.Missing.Value; //设置默认值,在之后的参数填充中使用
57 excel.DisplayAlerts = false; //设置不显示弹出对话框
58 excel.AlertBeforeOverwriting = false; //设置无提示直接重写文件
59 excelbook.SaveAs("D:\\abc.xlsx", XlFileFormat.xlOpenXMLWorkbook,missing,missing,missing,missing,XlSaveAsAccessMode.xlNoChange,missing,
60 missing,missing,missing,missing); //看到missing的作用了吧
61 excelbook.Close(true,"D:\\abc.xlsx",false); //关闭工作簿
62
63 // excelbook.SaveAs("D:\\abc.xls", XlFileFormat.xlExcel8, missing, missing, missing, missing, XlSaveAsAccessMode.xlNoChange, missing, //XlFileFormat.xlExcel8是2003格式,xlOpenXMLWorkbook是2007格式,查了不少资料才搞清楚,
64 //missing, missing, missing, missing);
65 // excelbook.Close(true, "D:\\abc.xls", false)
66
67 excel.Quit(); //退出Excel
68 //excel = null; 这句话理论上应该有用,但是实际没有。Excel进程依然存在,没有结束的迹象。只能杀进程。
69 killExcel(excel);
70
71
72 }
73 catch (Exception ex)
74 {
75
76 }
77
78
79
80 }
81
82 DBStatic.Dispose();
83
84
85 }
86 //以下来源于网络,这个方法有效,不过是在Excel没有出错的情况下。
87 private static void killExcel(Microsoft.Office.Interop.Excel._Application excel)
88 {
89 try
90 {
91 Process[] ps = Process.GetProcesses();
92 IntPtr t = new IntPtr(excel.Hwnd); //得到这个句柄,具体作用是得到这块内存入口
93 int ExcelID = 0;
94 GetWindowThreadProcessId(t, out ExcelID); //得到本进程唯一标志k
95 foreach (Process p in ps)
96 {
97 if (p.ProcessName.ToLower().Equals("excel"))
98 {
99 if (p.Id == ExcelID)
100 {
101 p.Kill();
102 }
103 }
104 }
105 }
106 catch (Exception ex)
107 {
108 }
109 }
110
111
112 }
113 }