C#自动更新Excel报表而不改变原有样式(2021.8.11)

Posted jing_zhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#自动更新Excel报表而不改变原有样式(2021.8.11)相关的知识,希望对你有一定的参考价值。

1、需求分析

        在日常的工作和学习生活中,很多单位需要进行统计分析生成Excel报表,报表文件是一个汇总性的文件,它的格式一般来说相对固定,而工作人员需要做的就是整理汇总,这个过程当中通常需要利用其它来源的原始数据表,也就是说需要将各方的Excel表格中的数据按照对应关系更新到指定的Excel报表文件中,如果采用传统的人工复制的方式则效率低下,可能会出错,工作量大;而此时则可以利用编程语言来提高办公的数据处理自动化效率并提高准确率,工作人员可将原来复制粘贴数据的时间用来检验数据是否更新正确,可以极大地缩短工作时间从而得心应手。

1.1 原始数据表(原始数据.xlsx

温度
湿度

        原始数据表Excel中包含 温度湿度 两个表,这两个表的结构相同,第一列都是站点点号第二列和第三列则是相邻两天的监测数据

1.2 Excel报表(20210811 报表.xlsx

        Excel报表中包含四个表,由于表中的点号往往不一定和原始数据中的点号相对应,同时天气原因会导致原始数据中的部分点号可能会观测不到数据,因此需要以原始数据为参考对这四个表中的昨天温度(湿度)和今天温度(湿度)两列数据按照站点号进行快速有效的更新

温度1-20
温度21-39
湿度1-20
湿度21-39

1.3 报表更新内容(复制粘贴后的效果)

        由于这里原始数据中的点号顺序和报表中要更新的点号顺序一致,所以传统复制粘贴的方式能够采用,但这种方式效率低下,在数据量大且点号顺序不一致时面临极大的不确定性和不准确性,当然非要使用复制粘贴也不是不可以,需要在原始数据表中按照更新报表中的站点号顺序来用宏筛选赋值后即可操作(主要利用IF、IFERROR和VLOOKUP三个函数,如:IF(IFERROR(VLOOKUP(A317,A23:G310,6,0),NA()),IFERROR(VLOOKUP(A1,A23:G310,6,0),NA()),NA())

温度1-20 更新后
温度21-39 更新后
湿度1-20 更新后
湿度21-39 更新后

2、目标实现

2.1 Excel文件类型分析(xls和xlsx)

        这里利用C#编程语言实现对Excel数据的操作,其中主要包含读取Excel数据写入Excel数据,而常见的Excel数据格式包含.xlsx.xls.csv等,这里主要操作的是xls和xlsx类型的Excel数据表。
        xls和xlsx的区别主要包含三个方面:

  • (1)文件格式不同
    • xls 是一个特有的二进制格式,其核心结构是复合文档类型的结构
    • 而xlsx 的核心结构是 XML 类型的结构,采用的是基于 XML 的压缩方式,使其占用的空间更小。xlsx 中最后一个 x 的意义就在于此。
  • (2)版本不同
    • xls是Excel 2003及以前版本生成的文件格式
    • 而xlsx是Excel 2007及以后版本生成的文件格式
  • (3)兼容性不同
    • xls 就是 Microsoft Excel 工作表,是一种非常常用的电子表格格式。xls文件可以使用Microsoft Excel打开,使用Microsoft Excel可以将XLS格式的表格转换为多种格式:XML表格、XML数据、网页、使用制表符分割的文本文件(.txt)、使用逗号分隔的文本文件(.csv)等。
    • xlsx是Microsoft Office Excel 2007/2010/2013/2016/2019文档的扩展名, xlsx格式是向下兼容的,可兼容xls格式,xlsx是从Office 2007开始使用的,是用新的基于XML的压缩文件格式取代了其目前专有的默认文件格式,在传统的文件名扩展名后面添加了字母x(即:docx取代doc、.xlsx取代xls等等),使其占用空间更小。

2.2 C# 解决Excel报表自动更新

         C# 是微软公司发布的一种由CC++衍生出来的面向对象的编程语言、运行于 .NET Framework.NET Core (完全开源,跨平台)之上的高级程序设计语言。

  1. C#是由C和C++衍生出来的一种安全的、稳定的、简单的、优雅的面向对象编程语言。它在继承C和C++强大功能的同时去掉了一些它们的复杂特性(例如没有以及不允许多重继承)。
  2. C#是面向对象的编程语言。它使得程序员可以快速地编写各种基于MICROSOFT .NET平台的应用程序,MICROSOFT .NET提供了一系列的工具和服务来最大程度地开发利用计算与通讯领域。
  3. C#使得C++程序员可以高效的开发程序,且因可调用由 C/C++ 编写的本机原生函数,而绝不损失C/C++原有的强大的功能。因为这种继承关系,C#与C/C++具有极大的相似性,熟悉类似语言的开发者可以很快的转向C#。

2.2.1 C#环境配置(VS2010+C#)

        首先参考微软官方帮助安装 Visual Studio来安装Microsoft Visual Studio,安装过程中记得选择编程语言C#(默认就是C#),安装完成即可,这里选择的是VS 2010版本,当然自己可以选择VS 2015VS 2017VS 2019均可。


2.2.2 新建C#项目

        第一步,打开VS 2010,新建项目选择Visual C#中的Windows窗体应用程序,之后输入项目名称点击确定。

        第二步,为了能够在C#Windows窗体应用程序中操作Excel,需要添加Excel引用,点击菜单栏中的项目->添加引用,在弹出的添加引用窗口中选择.NET中的Microsoft.Office.Interop.Excel后点击确定即可在右侧的解决方案资源管理器项目下的引用中看到是否添加进来。




        第三步,在解决方案院管理器中双击Form1.cs进入Form1窗体,利用左侧的工具箱向窗体中添加控件(5个Label标签、3个TextBox文本框、4个Button按钮、1个DataGridView数据网格视图、1个TabControl切换、1个StatusStrip状态栏和1个Timer定时器),窗体最终设计好的结果如下图所示。

2.2.3 编写C#代码

        C# .NET直接通过Excel接口来处理数据报表更新问题,只需在From1.cs中编写相应的功能代码。
                Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

namespace UpdateBaoBiaoExcelByAnatherExcel
{
    public partial class Form1 : Form
    {
        public Microsoft.Office.Interop.Excel.Application excelApp;
        public System.Data.DataTable dt;
        public int index = 1;
        public Form1()
        {
            this.StartPosition = FormStartPosition.CenterScreen;
            InitializeComponent();
            AllocConsole();
            Console.SetWindowPosition(0, 0);
            Console.WriteLine("欢迎使用 Excel数据文件自动更新报表系统 v1.0!");
        }

        [DllImport("kernel32.dll")]
        static extern bool FreeConsole();//调用系统API,释放用控制台窗口

        [DllImport("kernel32.dll")]
        public static extern bool AllocConsole();//调用系统API,调用控制台窗口

        private void button1_Click(object sender, EventArgs e)
        {
            this.label4.Visible = false;
            this.label5.Visible = false;
            this.tabControl1.Visible = false;
            this.dataGridView1.Visible = false;

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Multiselect = true;//该值确定是否可以选择多个文件
            dialog.Title = "请选择Excel数据文件";
            dialog.Filter = "Excel文件(*.xls,*.xlsx)|*.xls;*.xlsx";
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.textBox1.Text = dialog.FileName;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.label4.Visible = false;
            this.label5.Visible = false;
            this.tabControl1.Visible = false;
            this.dataGridView1.Visible = false;

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Multiselect = true;//该值确定是否可以选择多个文件
            dialog.Title = "请选择Excel报表文件";
            dialog.Filter = "Excel文件(*.xls,*.xlsx)|*.xls;*.xlsx";
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.textBox2.Text = dialog.FileName;
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            this.Close();
            FreeConsole();
            System.Windows.Forms.Application.Exit();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.textBox1.Text == "")
                {
                    MessageBox.Show("请选择Excel数据文件!");
                    return;
                }
                if (this.textBox3.Text == "")
                {
                    MessageBox.Show("请输入数据文件保存数据的sheet名!");
                    return;
                }
                if (this.textBox2.Text == "")
                {
                    MessageBox.Show("请选择要更新的Excel报表!");
                    return;
                }
                excelApp = new Microsoft.Office.Interop.Excel.Application();
                loadXls(this.textBox1.Text, this.textBox3.Text);
                Console.ForegroundColor = ConsoleColor.Green;
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        Console.Write(dt.Rows[i][j] + " ");
                    }
                    Console.WriteLine();
                }
                writeToXls(this.textBox2.Text, dt, this.textBox3.Text);
                this.label4.Visible = true;
                this.label5.Visible = true;
                this.tabControl1.Visible = true;
                this.dataGridView1.Visible = true;
                this.dataGridView1.DataSource = dt;
                Console.WriteLine("Finished");
                MessageBox.Show("Success!");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                excelApp.Quit();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
            }
        }
        public void loadXls(string path,string sheetName)
        {
            try
            {
                dt = new System.Data.DataTable(sheetName);
                dt.Columns.Add("站点号", Type.GetType("System.String"));
                dt.Columns.Add("昨天数据", Type.GetType("System.String"));
                dt.Columns.Add("今天数据", Type.GetType("System.String"));

                Workbook workBook = excelApp.Workbooks.Open(path);
                for (int sheeti = 1; sheeti <= workBook.Worksheets.Count; sheeti++)
                {
                    if (workBook.Worksheets[sheeti].Name.Contains(sheetName))
                    {
                        Worksheet workSheet = workBook.Worksheets[sheeti];
                        var usedRange = workSheet.UsedRange;
                        var rowCount = usedRange.Rows.Count;
                        var colCount = usedRange.Columns.Count;

                        int start_point_row = 2, end_point_row = rowCount, start_point_col = colCount - 1, end_point_col = colCount;
                        for (int i = start_point_row; i <= end_point_row; ++i)
                        {
                            DataRow dr = dt.NewRow();
                            String yesterday_data = workSheet.UsedRange.Cells[i, start_point_col].Value == null ? null : String.Format("{0:F}", workSheet.UsedRange.Cells[i, start_point_col].Value);
                            String today_data = workSheet.UsedRange.Cells[i, end_point_col].Value == null ? null : String.Format("{0:F}", workSheet.UsedRange.Cells[i, end_point_col].Value);
                            dr["站点号"] = workSheet.UsedRange.Cells[i, 1].Value;
                            dr["昨天数据"] = yesterday_data;
                            dr["今天数据"] = today_data;
                            dt.Rows.Add(dr);
                        }
                        break;
                    }
                }
                workBook.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        public void writeToXls(string path, System.Data.DataTable dt,string sheetname)
        {
            try
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Workbook workBook = excelApp.Workbooks.Open(path);
                int workSheetNum = 1;
                for (; workSheetNum <= workBook.Worksheets.Count; workSheetNum++)
                {
                    if (workBook.Worksheets[workSheetNum].Name.Contains(sheetname))
                    {
                        Worksheet workSheet = workBook.Worksheets[workSheetNum];
                        System.Data.DataTable dt_sheet = new System.Data.DataTable(workSheet.Name);
                        dt_sheet.Columns.Add("站点号", Type.GetType("System.String"));
                        dt_sheet.Columns.Add("昨天数据", Type.GetType("System.String"));
                        dt_sheet.Columns.Add("今天数据", Type.GetType("System.String"));
                        Console.WriteLine("*********修改报表中名字为" + workSheet.Name + " 的sheet内容如下:***********");
                        var rowCount = workSheet.UsedRange.Rows.Count;
                        int start_point_row = 1, end_point_row = 1;
                        for (int i = 1; i <= rowCount; i++)//先从第一列找点号
                        {
                            if (workSheet.UsedRange.Cells[i, 1].Value == "站点号")
                            {
                                start_point_row = i + 1;
                            }
                            if (workSheet.UsedRange.Cells[i, 1].Value == "结论:")
                            {
                                end_point_row = i; break;
                            }
                        }
                        for (int i = start_point_row; i <= end_point_row; ++i)
                        {
                            String pid = workSheet.UsedRange.Cells[i, 1].Value == null ? null : String.Format("{0}", workSheet.UsedRange.Cells[i, 1].Value);
                            int k = 0;
                            for (; k < dt.Rows.Count; k++)
                            {
                                String dt_pid = Convert.ToString(dt.Rows[k][0]);
                                if (dt_pid == pid)
                                {
                                    if (dt.Rows[k][1] != null)
                                        workSheet.Cells[i + 1, 3].Value = dt.Rows[k][1];
                                    if (dt.Rows[k][2] != null)
                                        workSheet.Cells[i + 1, 4].Value = dt.Rows[k][2];
                                    Console.WriteLine(dt.Rows[k][0] + "   " + dt.Rows[k][1] +"   "+ dt.Rows[k][2如何在Excel数据中间插入数据而不覆盖原有数据?

Excel设置表格样式的显示效果使用excel如何改变表格样式

NPOI使用ShiftRows向excel插入行,并复制原有样式

我所知道报表之POI创建Excel单元格填充数据设置样式绘制图形

C#生成excel到其他电脑生成报表时报错

C# 用openxml做excel报表怎么做。excel有模板。查询的数据填充到模板指定的单元格内