如果你耐心仔细看完本文,相信以后再遇到导出EXCLE操作的时候你会很顺手觉得SO EASY,主要给新手朋友们看的,老鸟可以直接飘过了,花了一晚上的时间写的很辛苦,如果觉得对你有帮助烦请留言支持一下,我会写更多基础的原创内容来回报大家。
C#导出数据到EXCEL表格是个老生常谈的问题了,写这篇文章主要是给和我一样的新手朋友提供两种导出EXCEL的方法并探讨一下导出的效率问题,本文中的代码直接就可用,其中部分代码参考其他的代码并做了修改,抛砖引玉,希望大家一起探讨,如有不对的地方还请大家多多包涵并指出来,我也是个新手,出错也是难免的。
本文所有打包文件请到我的下载频道去下载,附链接
http://download.csdn.net/source/1799748
首先先总结下自己知道的导出EXCEL表格的方法,大致有以下几种,有疏漏的请大家补充。
1.数据逐条逐条的写入EXCEL
2.通过OLEDB把EXCEL做为数据源来写
3.通过RANGE范围写入多行多列内存数据到EXCEL
4.利用系统剪贴板写入EXCEL
好了,我想这些方法已经足够完成我们要实现的功能了,方法不在多,在精,不是么?以上4中方法都可以实现导出EXCEL,方法1为最基础的方法,意思就是效率可能不是太高,当遇到数据量过大时所要付出的时间也是巨大的,后面3种方法都是第一种的衍生,在第一种方法效率低下的基础上改进的,这里主要就是一个效率问题了,当然如果你数据量都很小,我想4种方法就代码量和复杂程度来说第1种基本方法就可以了,或当你的硬件非常牛逼了,那再差的方法也可以高效的完成也没有探讨的实际意义了,呵呵说远了,本文主要是在不考虑硬件或同等硬件条件下单从软件角度出发探讨较好的解决方案。
此项目代码已打包在附件中,几乎注释的无微不至,在配合本文中我唐僧般的娓娓道来(靠,谁丢臭鸡蛋砸俺了),相信即使刚入门C#的朋友也能看得懂了吧,大家可以自行下载,代码中演示了两种方法,上述的方法1和方法3,我想足够了,方法3的效率应该是四种中最高的了,其他两种有兴趣的朋友自己实现下哈(方法2在我的程序中也有用到一些,看完你就知道了),程序如下图所示,先加载一个EXCEL表格进DATAGRIDVIEW作为数据源,然后两种方法导出EXCEL,配上一个计数功能给大家直观的看到导出的耗时,大家可以准备个几万行和十多行的两个EXCEL作为数据源来测试,也可以用我打包里的XLS来测试下。
首先使用前都需要加载COM组件Microsoft.Office.Interop.Excel.dll(已打包)
关键代码如下:
方法1,最基本方法,用FOR循环逐条写入EXCEL的CELL中,其他的看代码就行了,关键代码如下
- C# code
-
public void ToExcel2(DataGridView gridView, SaveFileDialog saveFileDialog)
-
{
-
....................
-
System.Reflection.Missing miss = System.Reflection.Missing.Value; //创建EXCEL对象appExcel,Workbook对象,Worksheet对象,Range对象
-
Microsoft.Office.Interop.Excel.Application appExcel;
-
appExcel = new Microsoft.Office.Interop.Excel.Application();
-
Microsoft.Office.Interop.Excel.Workbook workbookData;
-
Microsoft.Office.Interop.Excel.Worksheet worksheetData;
-
Microsoft.Office.Interop.Excel.Range rangedata; //设置对象不可见
-
appExcel.Visible = false;
-
/* 在调用Excel应用程序,或创建Excel工作簿之前,记着加上下面的两行代码 * 这是因为Excel有一个Bug,如果你的操作系统的环境不是英文的,而Excel就会在执行下面的代码时,报异常。 */
-
System.Globalization.CultureInfo CurrentCI = System.Threading.Thread.CurrentThread.CurrentCulture; System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
-
workbookData = appExcel.Workbooks.Add(miss);
-
worksheetData =(Microsoft.Office.Interop.Excel.Worksheet)workbookData.Worksheets.Add(miss, miss, miss, miss); //给工作表赋名称
-
worksheetData.Name = "saved"; //清零计数并开始计数
-
TimeP = new System.DateTime(0);
-
timer1.Start();
-
label1.Text = TimeP.ToString("HH:mm:ss"); // 保存到WorkSheet的表头,你应该看到,是一个Cell一个Cell的存储,这样效率特别低,解决的办法是,使用Rang,一块一块地存储到Excel
-
for (int i = 0; i < gridView.ColumnCount; i++)
-
{
-
worksheetData.Cells[1, i + 1] = gridView.Columns[i].HeaderText.ToString();
-
} //先给Range对象一个范围为A2开始,Range对象可以给一个CELL的范围,也可以给例如A1到H10这样的范围 //因为第一行已经写了表头,所以所有数据都应该从A2开始
-
rangedata = worksheetData.get_Range("A2", miss);
-
Microsoft.Office.Interop.Excel.Range xlRang = null; //iRowCount为实际行数,最大行
-
int iRowCount = gridView.RowCount;
-
int iParstedRow = 0,
-
iCurrSize = 0; //iEachSize为每次写行的数值,可以自己设置,每次写1000行和每次写2000行大家可以自己测试下效率
-
int iEachSize = 1000; //iColumnAccount为实际列数,最大列数
-
int iColumnAccount = gridView.ColumnCount; //在内存中声明一个iEachSize×iColumnAccount的数组,iEachSize是每次最大存 储的行数,iColumnAccount就是存储的实际列数
-
object[,] objVal = new object[iEachSize, iColumnAccount];
-
try {
-
//给进度条赋最大值为实际行数最大值
-
progressBar1.Maximum = gridView.RowCount;
-
iCurrSize = iEachSize;
-
while (iParstedRow < iRowCount)
-
{
-
if ((iRowCount - iParstedRow) < iEachSize)
-
iCurrSize = iRowCount - iParstedRow; //用FOR循环给数组赋值
-
for (int i = 0; i < iCurrSize; i++)
-
{
-
for (int j = 0; j < iColumnAccount; j++)
-
objVal[i, j] = gridView[j, i + iParstedRow].Value.ToString();
-
progressBar1.Value++;
-
System.Windows.Forms.Application.DoEvents(); } /* * 建议使用设置断点研究下哈 * 例如A1到H10的意思是从A到H,第一行到第十行 * 下句很关键,要保证获取Sheet中对应的Range范围 * 下句实际上是得到这样的一个代码语句xlRang = worksheetData.get_Range("A2","H100"); * 注意看实现的过程 * 'A' + iColumnAccount - 1这儿是获取你的最后列,A的数字码为65,大家可以仔细看下是不是得到最后列的字母 * iParstedRow + iCurrSize + 1获取最后行 * 若WHILE第一次循环的话这应该是A2,最后列字母+最后行数字 * iParstedRow + 2要注意,每次循环这个值不一样,他取决于你每次循环RANGE取了多大,循环了几次,也就是iEachSize设置值的大小哦 */
-
xlRang = worksheetData.get_Range("A" + ((int)(iParstedRow + 2)).ToString(), ((char)('A' + iColumnAccount - 1)).ToString() + ((int)(iParstedRow + iCurrSize + 1)).ToString()); // 调用Range的Value2属性,把内存中的值赋给Excel
-
xlRang.Value2 = objVal;
-
iParstedRow = iParstedRow + iCurrSize; } //保存工作表
-
worksheetData.SaveAs(strName, miss, miss, miss, miss, miss, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, miss, miss, miss); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRang);
-
xlRang = null;
-
progressBar1.Value = 0; //调用方法关闭EXCEL进程,大家可以试下不用的话如果程序不关闭在进程里一直会有EXCEL.EXE这个进程并锁定你的EXCEL表格
-
this.KillSpecialExcel(appExcel); timer1.Stop();
-
MessageBox.Show("数据已经成功导出到:" + saveFileDialog.FileName.ToString(), "导出完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
-
}
-
catch (Exception ex)
-
{
-
MessageBox.Show(ex.Message); timer1.Stop();
-
return;
-
} // 别忘了在结束程序之前恢复你的环境! System.Threading.Thread.CurrentThread.CurrentCulture = CurrentCI;
请发表评论