C# excel报表自动化

统计Excel表格是我们工作学习中会碰到的事情,对于批量报表的统计运算,编写程序对Excel表格处理是高效,错误率低的办法,总结一下我近期的学习情况。

1. 引用程序集

   Excel二次开发的程序集很多,我用的是VS自带的com组件,com组件的优点是实现功能完整,比较强大;缺点是代码很复杂,
   一写一长串,不易理解,而且接口繁多,很多我们日常基本用不上。
   首先需要在引用的COM中找到Microsoft Excel 16.0 Object Library(看各自版本),添加到引用中。

C# excel报表自动化_第1张图片

添加引用后,Using

	using MyExcel = Microsoft.Office.Interop.Excel;//起别名MyExcel
	using System.IO;

2. 读写Excel

使用Com组件读写Excel,需要创建一系列对象,自上而下为:
Excel进程Application,工作簿集合Workbooks,工作簿Workbook,工作表Worksheet,单元格
我们想要操作表格,读写数据,就要一步一步的创建下来。

Com组件读写excel表格,必须要打开Excel程序,所以要先创建Excel进程;

然后是工作簿,一个进程可以打开很多工作簿,就需要创建Workbooks对象,它是一个集合,可以包含多个Workbook,Workbook对象就对应单个excel文档,Workbook对象构成Workbooks,是Workbooks的子集。Workbooks由Excel进程打开;
最后是工作表,一个Workbook对象包含Worksheet,Worksheet是Workbook的子集。

主要操作包括Workbook(工作簿)的打开,新建,删除,另存;Worksheet(工作表)的新建,删除,获取;单元格的数据读取写入,格式公式的设置等。

示例一、
创建进程,创建工作簿集合,操作完成后要关闭工作簿和Excel进程,不然会在后台遗留,下次开机后会自动打开Excel,后边介绍杀进程的代码。

	    MyExcel.Application application = new MyExcel.Application();//创建名为application的Excel进程
            application.Visible = true;//设置可见性,false的话程序全程在后台运行,不会看到
            application.DisplayAlerts = false;//不现实提示对话框
            MyExcel.Workbooks workbooks = application.Workbooks;//创建名为workbooks的工作簿集合
            
            workbooks.Close();//关闭工作簿
            application.Quit();//退出进程

示例二、
文档操作,新建与打开

            MyExcel.Application application = new MyExcel.Application();
            application.Visible = true;
            application.DisplayAlerts = false;//不现实提示对话框
            MyExcel.Workbooks workbooks = application.Workbooks;
            MyExcel.Workbook wb = workbooks.Add("文档路径");//新建wb的工作簿对象,它为我们打开创建的文件
            MyExcel.Workbook wb1 = workbooks.Open("文档路径");
            wb.Save();
            wb1.Save();//com组件直接对文档操作,所以处理文档后一定要Save
            workbooks.Close();
            application.Quit();

注:workbooks的Add()方法,若有路径参数,可打开文档,若不输入参数,则表示新建文档,需要用 wb.SaveAs()方法保存出来。
workbooks的Open()方法只用于打开文件。

示例三、
工作表获取,新建与删除

            MyExcel.Application application = new MyExcel.Application();
            application.Visible = true;
            application.DisplayAlerts = false;//不现实提示对话框
            MyExcel.Workbooks workbooks = application.Workbooks;
            MyExcel.Workbook wb = workbooks.Open(@"C:\Userdata\EX0122\3.xlsx");
            
            //以下两种读取工作表的方法,索引和名称,名称可能报错
            MyExcel.Worksheet wsheet = wb.Sheets[1];//工作表索引从1开始,不是0
            //MyExcel.Worksheet wsheet1 = (MyExcel.Worksheet)wb.Worksheets["义教经费支出明细表"];
            
            wsheet.Activate();//激活才可以操作工作表
            wsheet.Name = "表名AAA";//工作表更改名称

	    //新建工作表
	    object missing = Missing.Value;//创建缺省值,需要using
            MyExcel.Worksheet newsheet = (MyExcel.Worksheet)wb.Worksheets.Add(missing, missing, 1, missing);//默认新建到最前边

	    //删除工作表,两种方法
	    newsheet.Delete();//表对象的Delete()方法就可删除	    
	    //string sheetName = "Sheet1";//通过表名称删除
            //((MyExcel.Worksheet)wb.Worksheets[sheetName]).Delete();
            
            wb.Save();
            workbooks.Close();
            application.Quit();

示例四、
单元格数据读取,C#中有Range对象和Cells对象。顾名思义,range是区域的意思,cells是单元格的意思,range包含cells。
一个 Range 对象可以代表一个单元格、一行、一列、包含一个或者更多单元块(可以是连续的单元格,也可以式不连续的单元格)的选定单元格,甚至是多个工作表上的一组单元格。而单独用cells只能获取获取一个单元格的数据。
若要获取excel中A1到E5的区域,当然用Range对象会得心应手。或者用cells和循环读取。

//激活工作表后接如下代码
//获取单个单元格,行列的索引都是从1开始,不是0
            //1、直接取出单元格的值,值类型转换,一定要有.Value才是取出来的值
            string value = Convert.ToString(wsheet.Cells[17, 1].Value);
            //2、新建range对象,将单元格强转为range对象,列号用字母索引也可
            MyExcel.Range range = (MyExcel.Range)wsheet.Cells[17, "A"];
            string value1 = Convert.ToString(range.Value);
            //3、也可以用如下方法
            MyExcel.Range range1 = wsheet.Range["A17"];
            string value2 = Convert.ToString(range.Value)
//获取区域数据
            object[,] data = wsheet.Range["D9:H11"].Value;//赋给数组也可以

           

注意:
1、拿取值要转换range.Value得到的才是对的,range.Text可能是单元格的显示内容,
C# excel报表自动化_第2张图片
比如,A17单元格的值为333.123,range.Text拿到的值是带格式的值¥333.12,或者是省略小数的
2、对于大规模数据,用Range对象整个读到数组中再循环处理,要比一个单元格一个单元格取值快N倍。

示例五、
数据写入
格式的调整功能很多,暂时就摸索这么多吧,对于报表统计运算这么多内容就够了吧,后边学了再来补

            //用行列索引直接赋值
	    wsheet.Cells[17, 1].Value = "表二";
	    //用Range对象,写入表格
            MyExcel.Range range3 = (MyExcel.Range)wsheet.Cells[19, "A"];
            range3.Value = "";
            range3.Formula = "=A18";//公式
            range3.Font.Name = "宋体";//字体
            range3.Font.Size = 12;//字号
            range3.Font.Color = Color.Red;//字体颜色


            //合并单元格
            MyExcel.Range range4 = wsheet.Range["D14:D15"];//选择区域,用Merge()方法,合并后的值默认为区域左上单元格的值
            range4.Merge();

1

3. 其他问题

1、批量读取excel表格后,虽然退出了进程,(application.Quit();),但后台还有。。。

C# excel报表自动化_第3张图片

网上找了杀进程的办法,

[DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
        public static void Kill(Microsoft.Office.Interop.Excel.Application excel)
        {
     
            IntPtr t = new IntPtr(excel.Hwnd);//得到这个句柄,具体作用是得到这块内存入口 
            int k = 0;
            GetWindowThreadProcessId(t, out k);   //得到本进程唯一标志k
            System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k);   //得到对进程k的引用
            p.Kill();     //关闭进程k
        }

直接调用该方法,把我们创建的application传进去就可

 try
            {
     
                //杀进程
                Kill(application);
                //释放EXCEL应用程序的进程
                System.Runtime.InteropServices.Marshal.ReleaseComObject(application);
            }
            catch
            {
      }

2、单元个字母索引和数字索引的转换,10进制与26进制转换

/// 
        /// 用于excel表格中列号字母转成列索引,从1对应A开始
        /// 
        /// 列号
        /// 列索引
        public static int ColumnToIndex(string column)
        {
     
            int index = 0;
            char[] chars = column.ToUpper().ToCharArray();
            for (int i = 0; i < chars.Length; i++)
            {
     
                index += ((int)chars[i] - (int)'A' + 1) * (int)Math.Pow(26, chars.Length - i - 1);
            }
            return index;
        }
        /// 
        /// 用于将excel表格中列索引转成列号字母,从A对应1开始
        /// 
        /// 列索引
        /// 列号
        private static string IndexToColumn(int index)
        {
     
            if (index <= 0)
            {
     
                throw new Exception("Invalid parameter");
            }
            index--;
            string column = string.Empty;
            do
            {
     
                if (column.Length > 0)
                {
     
                    index--;
                }
                column = ((char)(index % 26 + (int)'A')).ToString() + column;
                index = (int)((index - index % 26) / 26);
            } while (index > 0);
            return column;
        }
        //行列号转换为字母索引
        public static string TransIndex(int row, int column)
        {
     
            string a = IndexToColumn(column);
            return a + row.ToString();
        }

你可能感兴趣的:(C#操作excel,c#)