在日常的工作和学习生活中,很多单位需要进行统计分析生成Excel报表,报表文件是一个汇总性的文件,它的格式一般来说相对固定,而工作人员需要做的就是整理汇总
,这个过程当中通常需要利用其它来源的原始数据表,也就是说需要将各方的Excel表格中的数据按照对应关系更新到指定的Excel报表文件中,如果采用传统的人工复制的方式则效率低下,可能会出错,工作量大;而此时则可以利用编程语言来提高办公的数据处理自动化效率并提高准确率,工作人员可将原来复制粘贴数据的时间用来检验数据是否更新正确,可以极大地缩短工作时间从而得心应手。
原始数据.xlsx
)
|
|
原始数据表Excel中包含 温度 和 湿度 两个表,这两个表的结构相同,第一列都是站点点号,第二列和第三列则是相邻两天的监测数据。
20210811 报表.xlsx
)Excel报表中包含四个表,由于表中的点号往往不一定和原始数据中的点号相对应,同时天气原因会导致原始数据中的部分点号可能会观测不到数据,因此需要以原始数据为参考对这四个表中的昨天温度(湿度)和今天温度(湿度)两列数据按照站点号进行快速有效的更新。
|
|
|
|
由于这里原始数据中的点号顺序和报表中要更新的点号顺序一致,所以传统复制粘贴的方式能够采用,但这种方式效率低下,在数据量大且点号顺序不一致时面临极大的不确定性和不准确性,当然非要使用复制粘贴也不是不可以,需要在原始数据表中按照更新报表中的站点号顺序来用宏筛选赋值后即可操作(主要利用IF、IFERROR和VLOOKUP三个函数,如:IF(IFERROR(VLOOKUP(A317,A23:G310,6,0),NA()),IFERROR(VLOOKUP(A1,A23:G310,6,0),NA()),NA())
)
|
|
|
|
这里利用C#
编程语言实现对Excel数据的操作,其中主要包含读取Excel数据和写入Excel数据,而常见的Excel数据格式包含.xlsx
、.xls
和.csv
等,这里主要操作的是xls和xlsx类型的Excel数据表。
xls和xlsx的区别主要包含三个方面:
C# 是微软公司发布的一种由C
和C++
衍生出来的面向对象的编程语言、运行于 .NET Framework 和 .NET Core (完全开源,跨平台)之上的高级程序设计语言。
宏
以及不允许多重继承)。 首先参考微软官方帮助安装 Visual Studio来安装Microsoft Visual Studio,安装过程中记得选择编程语言C#
(默认就是C#),安装完成即可,这里选择的是VS 2010版本,当然自己可以选择VS 2015、VS 2017和VS 2019均可。
第一步,打开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定时器
),窗体最终设计好的结果如下图所示。
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]);
String yesterday_data = workSheet.UsedRange.Cells[i, 3].Value == null ? null : String.Format("{0:F}", workSheet.UsedRange.Cells[i, 3].Value);
String today_data = workSheet.UsedRange.Cells[i, 4].Value == null ? null : String.Format("{0:F}", workSheet.UsedRange.Cells[i, 4].Value);
DataRow dr_sheet = dt_sheet.NewRow();
dr_sheet["站点号"] = workSheet.UsedRange.Cells[i, 1].Value;
dr_sheet["昨天数据"] = yesterday_data;
dr_sheet["今天数据"] = today_data;
dt_sheet.Rows.Add(dr_sheet);
break;
}
}
}
TabPage Page = new TabPage();
Page.Name = workSheet.Name;
Page.Text = workSheet.Name;
Page.TabIndex = index++;
Page.SuspendLayout();
DataGridView grid = new DataGridView();
grid.DataSource = dt_sheet;
grid.ScrollBars = System.Windows.Forms.ScrollBars.Both;
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle = new System.Windows.Forms.DataGridViewCellStyle();
grid.AllowUserToAddRows = false;
grid.AllowUserToDeleteRows = false;
grid.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
grid.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle;
grid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridViewCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
grid.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle;
grid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
Page.Controls.Add(grid);
Page.ResumeLayout();
Page.Refresh();
this.tabControl1.Controls.Add(Page);
}
}
workBook.Save();
workBook.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Form1_Load(object sender, EventArgs e)
{
this.timer1.Interval = 1000;
this.timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
this.toolStripStatusLabel1.Text = "您好,欢迎使用本系统!" + "当前时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
}
}
原始数据文件原始数据.xlsx
和要更新的Excel报表文件20210811 报表.xlsx
最后点击菜单栏下调试中的开始执行(不调试)即可启动运行,运行界面如下图所示,其中左侧命令行窗口为日志窗口,右侧为程序主界面,需要选择原始数据文件和要更新的报表文件,同时输入数据表名后点击确定即可。(注:项目功能为将原始数据Excel文件中指定表中的数据更新到报表Excel文件中相关联的表中)
|
|
|
|
由于C#
操作Excel
读写数据时调用的是微软Microsoft
下办公软件Office
下的Excel
接口,因此采用C#代码进行的操作本质上等同于人工手动打开Excel应用来操作数据,从而实现一定的准确性和有效性,大数据量才会使得程序耗费较长的执行时间。