C#利用NPOI实现跨Excel数据查找(备件筛选工具)

2024-01-17 18:20

本文主要是介绍C#利用NPOI实现跨Excel数据查找(备件筛选工具),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  备件筛选工具,软件试用链接:https://download.csdn.net/download/weixin_44834086/12404203

备件筛选工具试用链接:https://download.csdn.net/download/weixin_44834086/12404203
软件演示视频链接:https://www.bilibili.com/video/BV145411s7fu/
设备工程师最常见的一项工作就是备件清单梳理,每次当供应商提供一份元器件清单给我我们后,我们会先进行初步筛选,选出哪些是我们需要的,形成初步的备件清单,但这个清单不能直接提交给采购部,因为这个清单里可能存在库房里已经有的备件,这部分已经有的备件是不需要买的,我们必须把它们筛选出来删掉,才能提交给采购部购买。

怎样才能知道哪些备件是库房里已经有的呢?
你是不是会一个个的在库房台账Excel里按Ctrl+F查找?
或者你把初版备件清单复制到库房台账的Excel里,标记重复项?
当然,这是其中的两种方法,可是你有没有想过,这两种方法是不是就一定能达到我们的目的?
你想想下面这种情况:一个备件供应商提供的型号是“QSL-1/4-10”,但库房台账里的型号却是“QSL 1/4-10”,型号里只是多一个“-”,此时用上述的两种方法搜索是没有匹配的结果的,但实际上这两个型号是一样的,这时你会认为库房买有,结果买回来后发现库房有相同的备件,造成浪费。(别说了,说多了都是泪,库房里还有好多型号不同但东西是一样的的备件)。

这个事情没人管吗???!!!

于是我就开发这个备件筛选工具,就是为了解决上面这个问题,该工具可以设置搜索的相似精度,备件型号里的特殊字符都会过滤掉,把可能相同的备件全部筛选出来,给设备工程师判断这些备件是否一样提供一个参考,避免备件的重复购买。

如有bug欢迎提出,谢谢。
软件界面如下所示:在这里插入图片描述
如下图所示,设置搜索的相似精度为85%,软件完成搜索后会将搜索结果显示在窗体下方的DateGridView中,文件1中的哪一行,与文件2中的哪一行有相似的备件,设备工程师可以两个型号进行对比确认备件是否相同。
在这里插入图片描述
程序主要有以下功能:
1、字符串处理(过滤字符串中的特殊字符);
2、引用了两种字符串相似度的算法,并取两种算法算出的较大结果作为筛选的结果(可以避免漏选);
3、生成结果清单(使用NPOI创建Excel文件,并将DateGridView中的数据写入Excel文件);
4、生成备件清单(复制一份文件1,再使用NPOI将筛选出来的行删掉)

主要代码如下:

using System;
using System.Linq;
using System.Windows.Forms;
using F23.StringSimilarity;
using NP = NPOI.XSSF.UserModel;
using System.IO;
using System.Threading;
using NPOI.HSSF.UserModel;
using System.Drawing;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System.Collections;namespace 备件筛选工具
{public partial class Form1 : Form{public Form1(){InitializeComponent();Control.CheckForIllegalCrossThreadCalls = false;//程序加载时取消跨线程操作的访问                                            X = this.Width;//获取窗体的宽度Y = this.Height;//获取窗体的高度setTag(this);//调用方法}NPOI.SS.UserModel.ISheet sht1;//声明一个sheet  sht1NPOI.SS.UserModel.ISheet sht2;//声明一个sheet  sht2string FilePath1 = "";//声明字符串变量 文件1路径string FilePath2 = "";//声明字符串变量 文件2路径string fileName1 = "";string fileName2 = "";ArrayList matchRow = new ArrayList();//选择文件1private void Btn_Select1_Click(object sender, EventArgs e){OpenFileDialog ofd1 = new OpenFileDialog();ofd1.InitialDirectory = @"C:\Users\28463\Desktop";//定义打开文件对话框的初始目录ofd1.Title = "请选择要筛选的文件";//定义打开文件对话框的名称ofd1.Filter = "所有文件|*.xls;*.xlsx";//过滤只显示Excel文件ofd1.ShowDialog(); //弹出打开文件对话框fileName1 = System.IO.Path.GetFileName(ofd1.FileName);//将文件1的名称赋值给文本框fileNametext_FilePath1.Text = fileName1;//将文件1的名称赋值给文本框text_FilePath1.TextFilePath1 = ofd1.FileName;//将文件1的路径赋值给FilePath1}//选择文件2private void Btn_Select2_Click(object sender, EventArgs e){OpenFileDialog ofd2 = new OpenFileDialog();ofd2.InitialDirectory = @"C:\Users\28463\Desktop";//定义打开文件对话框的初始目录ofd2.Title = "请选择要筛选的文件";//定义打开文件对话框的名称ofd2.Filter = "所有文件|*.xls;*.xlsx";//过滤只显示Excel文件ofd2.ShowDialog();//弹出打开文件对话框fileName2 = System.IO.Path.GetFileName(ofd2.FileName);//将文件2的名称赋值给文本框fileNametext_FilePath2.Text = fileName2;//将文件2的名称赋值给文本框text_FilePath2.Text            FilePath2 = ofd2.FileName;//将文件2的路径赋值给FilePath1           }private void OpenFile1_Click(object sender, EventArgs e){try{System.Diagnostics.Process.Start(FilePath1);}catch (Exception ex){MessageBox.Show(ex.Message.ToString() + "\r\n" + "请检查是否选择文件!", "错误提示"); //抛出异常信息}}private void OpenFile2_Click(object sender, EventArgs e){try{System.Diagnostics.Process.Start(FilePath2);}catch (Exception ex){MessageBox.Show(ex.Message.ToString() + "\r\n" + "请检查是否选择文件!", "错误提示"); //抛出异常信息}}#region 过滤掉字符串中的特殊字符/// <summary>/// 过滤掉字符串中的特殊字符/// </summary>/// <param name="str">需要过滤字符串</param>/// <returns>过滤之后的字符串</returns>public static string ReplaceSymbol(string str){if (str == String.Empty)return String.Empty;//半角符号str = str.Replace("'", "");str = str.Replace("·", "");str = str.Replace(".", "");str = str.Replace(",", "");str = str.Replace(";", "");str = str.Replace(",", "");str = str.Replace("?", "");str = str.Replace("-", "");str = str.Replace("_", "");str = str.Replace("/", "");str = str.Replace("(", "(");str = str.Replace(")", ")");str = str.Replace("\\", "");//全角符号str = str.Replace(";", "");str = str.Replace(",", "");str = str.Replace("?", "");str = str.Replace("——", "");str = str.Replace("、", "");str = str.Replace("(", "");str = str.Replace(")", "");str = str.Replace("。", "");return str;}#endregion#region 利用Levenshtein方法计算两个字符串的相似率/// <summary>/// 利用Levenshtein方法计算两个字符串的相似率/// </summary>/// <param name="str1">字符串1</param>/// <param name="str2">字符串2</param>/// <returns>相似率</returns>private double Similarity1(string str1, string str2){str1 = ReplaceSymbol(str1).ToLower();//将字符串str1中的特殊符号去掉,并把字母变成小写str2 = ReplaceSymbol(str2).ToLower();//将字符串str2中的特殊符号去掉,并把字母变成小写double maxlen = str1.Length > str2.Length ? str1.Length : str2.Length;//取两个字符串长度中的较大的值,赋值给maxlenvar le = new Levenshtein();//实例化一个名称为le的Levenshtein对象,用于求从一个字符串变换到另一个字符串所需要的最短距离(步骤)double SimilarityRate = (1 - le.Distance(str1, str2) / maxlen);//计算相似率,其中le.Distance(str1,str2)为两个字符串转换的最短路径(步骤)return SimilarityRate;//返回相似率}#endregion#region 计算字符串相似度/// <summary>/// 获取两个字符串的相似度/// </summary>/// <param name=”str1”>第一个字符串</param>/// <param name=”str2”>第二个字符串</param>/// <returns></returns>private double Similarity2(string str1, string str2){str1 = ReplaceSymbol(str1).ToLower();str2 = ReplaceSymbol(str2).ToLower();double Kq = 2;double Kr = 1;double Ks = 1;char[] ss = str1.ToCharArray();char[] st = str2.ToCharArray();//获取交集数量int q = ss.Intersect(st).Count();int s = ss.Length - q;int r = st.Length - q;return Kq * q / (Kq * q + Kr * r + Ks * s);}#endregionprivate bool IsContain(string str1, string str2){str1 = ReplaceSymbol(str1).ToLower();str2 = ReplaceSymbol(str2).ToLower();return str2.Contains(str1);}private void Btn_SearchSimilarity_Click(object sender, EventArgs e){flag_SearchStop = false;btn_Stop.Focus();matchRow.Clear();//清空集合matchRow中的数据dataGridView1.Rows.Clear();//清除dataGridView1表格数据btn_SearchContain.Enabled = false;SearchSimilarity();//调用“搜索相似”方法btn_SearchContain.Enabled = true;}private void Btn_SearchContain_Click(object sender, EventArgs e){flag_SearchStop = false;btn_Stop.Focus();matchRow.Clear();//清空集合matchRow中的数据dataGridView1.Rows.Clear();//清除dataGridView1表格数据btn_SearchSimilarity.Enabled = false;SearchContain();//调用“搜索包含”方法btn_SearchSimilarity.Enabled = true;}/// <summary>/// 根据不同格式的Excel获取sheet(因为xlsx格式的Excel和xls格式的Excel获取sheet的方式不一样)/// </summary>/// <param name="FilePath">文件路径</param>/// <param name="fileName">文件名</param>/// <returns></returns>private NPOI.SS.UserModel.ISheet GetSheet(string FilePath, string fileName, int sheetIndex){FileStream fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);//必须要选择flieShare方式为ReadWrite,这样就可以在文件被打开的时候读取文件信息。if ((fileName.Split('.')[fileName.Split('.').Length - 1]).ToLower() == "xlsx")//判断文件1的文件名最后一个.后的字符串是否为xlsx{NP.XSSFWorkbook wk = new NP.XSSFWorkbook(fs);//实例化一个.xlsx格式的工作簿NPOI.SS.UserModel.ISheet sht = wk.GetSheetAt(sheetIndex);//根据“选择sheet”下拉列表框,获取工作表return sht;}else //((fileName1.Split('.')[fileName1.Split('.').Length - 1]).ToLower() == "xls")//判断文件1的文件名最后一个.后的字符串是否为xls{HSSFWorkbook wk = new HSSFWorkbook(fs);//实例化一个.xls格式的工作簿NPOI.SS.UserModel.ISheet sht = wk.GetSheetAt(sheetIndex);//根据“选择sheet”下拉列表框,获取工作表return sht;}}bool flag_SearchStop = false;private void SearchSimilarity(){try{sht1 = GetSheet(FilePath1, fileName1, comboBox_sheet1.SelectedIndex);sht2 = GetSheet(FilePath2, fileName2, comboBox_sheet2.SelectedIndex);int rowsCount1 = sht1.LastRowNum;//获取工作表sht1的有效行数int rowsCount2 = sht2.LastRowNum;//获取工作表sht2的有效行数int listNumber = Convert.ToInt32(comboBox_list1.SelectedIndex);//根据“选择列:”下拉列表框的选择索引号,获取列                progressBar1.Visible = true;//显示进度条progressBar1.Maximum = rowsCount1;//设置进度条的最大值为sht1的行数+1lbl_ProgressbarValue.Visible = true;//显示进度条百分比for (int i = Convert.ToInt32(comboBox_Row1.Text) - 1; i <= rowsCount1; i++)//i为sht1的行数索引{progressBar1.Value = i;//定义进度条的值为ilbl_ProgressbarValue.Text = (i * 100 / progressBar1.Maximum).ToString() + "%";//将进度条百分比赋值给文本框Application.DoEvents();//重点,必须加上,否则窗体会假死if (progressBar1.Value == progressBar1.Maximum){MessageBox.Show("搜索完成,搜到" + (dataGridView1.Rows.Count - 1).ToString() + "个结果!", "搜索结果提示");progressBar1.Value = 0;//将进度条数据置零progressBar1.Visible = false;//隐藏进度条lbl_ProgressbarValue.Visible = false;//隐藏进度条百分比 btn_SaveSearchResult.Enabled = true;//搜索完成后使能“保存搜索结果”按钮btn_CreateResultExcel.Enabled = true;//搜索完成后使能“生成备件清单”按钮}if (!flag_SearchStop){if (sht1.GetRow(i).GetCell(listNumber) != null)//如果sht1第i行第listNumber列不为空{string str1 = GetCellValue(sht1, i, listNumber);if (str1 == ""){continue;//如果读取的sht1第i行,第listNumber列单元格的字符串的值为空,则跳出当前循环,进入下一循环}else      //如果读取的sht1第i行,第listNumber列单元格的字符串的值不为空,则继续按下述循环判断sht2中的数据{for (int j = Convert.ToInt32(comboBox_Row2.Text) - 1; j <= rowsCount2; j++)//j为sht2的行数索引{if (sht2.GetRow(j) != null){if (comboBox_list2.Text == "搜索全部列"){for (int k = sht2.GetRow(j).FirstCellNum; k <= sht2.GetRow(j).LastCellNum; k++)//K为sht2的列数索引(或单元格索引){if (sht2.GetRow(j).GetCell(k) != null)      //如果sht2的第j行,第k列的单元格数据不为空{string str2 = GetCellValue(sht2, j, k);if (str2 == ""){continue;//如果读取的sht2第j行,第k列单元格的字符串的值为空,则跳出当前循环,进入下一循环}else         //如果读取的sht2第j行,第k列单元格的字符串的值不为空,执行如下比较字符串相似度的语句{double Simi = Similarity1(str1, str2) > Similarity2(str1, str2) ? Similarity1(str1, str2) : Similarity2(str1, str2);if (Simi >= Convert.ToDouble(comboBox_accuracy.Text) / 100){WriteToDateGridView(i, j, str1, str2);  //调用 WriteToDateGridView函数,将搜索结果显示到dateGridView里 ListAdd(i);//将匹配的行数存入集合中}}}else{continue;//如果sht1第i行第listNumber列为空,则跳出当前循环,进入下一循环;}}}else   //如果sheet2选择了列,则不搜索全部列,只搜索选择的列,可以大大减少搜索次数,提高搜索速度{if (sht2.GetRow(j).GetCell(comboBox_list2.SelectedIndex - 1) != null)      //如果sht2的第j行,第k列的单元格数据不为空{string str2 = GetCellValue(sht2, j, comboBox_list2.SelectedIndex - 1);if (str2 == ""){continue;//如果读取的sht2第j行,第k列单元格的字符串的值为空,则跳出当前循环,进入下一循环}else         //如果读取的sht2第j行,第k列单元格的字符串的值不为空,执行如下比较字符串相似度的语句{double Simi = Similarity1(str1, str2) > Similarity2(str1, str2) ? Similarity1(str1, str2) : Similarity2(str1, str2);if (Simi >= Convert.ToDouble(comboBox_accuracy.Text) / 100){WriteToDateGridView(i, j, str1, str2); //调用 WriteToDateGridView函数,将搜索结果显示到dateGridView里ListAdd(i);//将匹配的行数存入集合中}}}else{continue;//如果sht1第i行第listNumber列为空,则跳出当前循环,进入下一循环;}}}else{continue;}}}}else{continue;}}else{break;}}}catch (Exception ex){MessageBox.Show(ex.Message.ToString() + "\r\n" + "1.请检查是否选择文件!" + "\r\n" + "2.请检查文件的sheet和列是否选择正确!", "错误提示"); //抛出异常信息}}private void SearchContain(){try{sht1 = GetSheet(FilePath1, fileName1, comboBox_sheet1.SelectedIndex);sht2 = GetSheet(FilePath2, fileName2, comboBox_sheet2.SelectedIndex);int rowsCount1 = sht1.LastRowNum;//获取工作表sht1的有效行数int rowsCount2 = sht2.LastRowNum;//获取工作表sht2的有效行数int listNumber = Convert.ToInt32(comboBox_list1.SelectedIndex);//根据“选择列:”下拉列表框的选择索引号,获取列                progressBar1.Visible = true;//显示进度条progressBar1.Maximum = rowsCount1;//设置进度条的最大值为sht1的行数+1lbl_ProgressbarValue.Visible = true;//显示进度条百分比for (int i = Convert.ToInt32(comboBox_Row1.Text) - 1; i <= rowsCount1; i++)//i为sht1的行数索引{progressBar1.Value = i;//定义进度条的值为ilbl_ProgressbarValue.Text = (i * 100 / progressBar1.Maximum).ToString() + "%";//将进度条百分比赋值给文本框Application.DoEvents();//重点,必须加上,否则窗体会假死if (progressBar1.Value == progressBar1.Maximum){MessageBox.Show("搜索完成,搜到" + (dataGridView1.Rows.Count - 1).ToString() + "个结果!", "搜索结果提示");progressBar1.Value = 0;//将进度条数据置零progressBar1.Visible = false;//隐藏进度条lbl_ProgressbarValue.Visible = false;//隐藏进度条百分比                        }if (!flag_SearchStop){if (sht1.GetRow(i).GetCell(listNumber) != null)//如果sht1第i行第listNumber列不为空{string str1 = GetCellValue(sht1, i, listNumber);if (str1 == ""){continue;//如果读取的sht1第i行,第listNumber列单元格的字符串的值为空,则跳出当前循环,进入下一循环}else      //如果读取的sht1第i行,第listNumber列单元格的字符串的值不为空,则继续按下述循环判断sht2中的数据{for (int j = Convert.ToInt32(comboBox_Row2.Text) - 1; j <= rowsCount2; j++)//j为sht2的行数索引{if (sht2.GetRow(j) != null){if (comboBox_list2.Text == "搜索全部列"){for (int k = sht2.GetRow(j).FirstCellNum; k <= sht2.GetRow(j).LastCellNum; k++)//K为sht2的列数索引(或单元格索引){if (sht2.GetRow(j).GetCell(k) != null)      //如果sht2的第j行,第k列的单元格数据不为空{string str2 = GetCellValue(sht2, j, k);if (str2 == ""){continue;//如果读取的sht2第j行,第k列单元格的字符串的值为空,则跳出当前循环,进入下一循环}else         //如果读取的sht2第j行,第k列单元格的字符串的值不为空,执行如下比较字符串相似度的语句{if (IsContain(str1, str2)){WriteToDateGridView(i, j, str1, str2);  //调用 WriteToDateGridView函数,将搜索结果显示到dateGridView里 ListAdd(i);//将匹配的行数存入集合中}}}else{continue;//如果sht1第i行第listNumber列为空,则跳出当前循环,进入下一循环;}}}else    //如果sheet2选择了列,则不搜索全部列,只搜索选择的列,可以大大减少搜索次数,提高搜索速度{if (sht2.GetRow(j).GetCell(comboBox_list2.SelectedIndex - 1) != null)      //如果sht2的第j行,第k列的单元格数据不为空{string str2 = GetCellValue(sht2, j, comboBox_list2.SelectedIndex - 1);if (str2 == ""){continue;//如果读取的sht2第j行,第k列单元格的字符串的值为空,则跳出当前循环,进入下一循环}else         //如果读取的sht2第j行,第k列单元格的字符串的值不为空,执行如下比较字符串相似度的语句{if (IsContain(str1, str2)){WriteToDateGridView(i, j, str1, str2); //调用 WriteToDateGridView函数,将搜索结果显示到dateGridView里 ListAdd(i);//将匹配的行数存入集合中}}}else{continue;//如果sht1第i行第listNumber列为空,则跳出当前循环,进入下一循环;}}}else{continue;}}}}else{continue;}}else{break;}}}catch (Exception ex){MessageBox.Show(ex.Message.ToString() + "\r\n" + "1.请检查是否选择文件!" + "\r\n" + "2.请检查文件的sheet和列是否选择正确!", "错误提示"); //抛出异常信息}}private void Btn_Clear_Click(object sender, EventArgs e){dataGridView1.Rows.Clear();//清除dataGridView1表格数据matchRow.Clear();//清空集合matchRow中的数据progressBar1.Value = 0;//将进度条数据置零progressBar1.Visible = false;//隐藏进度条lbl_ProgressbarValue.Visible = false;//隐藏进度条百分比btn_SaveSearchResult.Enabled = false;//让“保存搜索结果”按钮无效btn_CreateResultExcel.Enabled = false;//让“生成备件清单”按钮无效//button1.Visible = true;}/// <summary>/// 将搜索结果显示到dateGridView里/// </summary>/// <param name="i">str1所在的行数</param>/// <param name="j">str1所在的行数</param>/// <param name="str1">sheet1中的字符串</param>/// <param name="str2">sheet2中的字符串</param>private void WriteToDateGridView(int i, int j, string str1, string str2){int index = this.dataGridView1.Rows.Add();this.dataGridView1.Rows[index].Cells[0].Value = (index + 1).ToString();this.dataGridView1.Rows[index].Cells[1].Value = "第" + (i + 1).ToString() + "行";this.dataGridView1.Rows[index].Cells[2].Value = str1;this.dataGridView1.Rows[index].Cells[3].Value = "第" + (j + 1).ToString() + "行";this.dataGridView1.Rows[index].Cells[4].Value = str2;}private string GetCellValue(NPOI.SS.UserModel.ISheet sht, int i, int j){string str = "";//声明字符串变量str2string cell_Type = sht.GetRow(i).GetCell(j).CellType.ToString();//获取sht2第j行,第k列单元格的数据格式,并赋值给字符串变量cell_Type2 switch (cell_Type)    //根据单元格里的数据格式读取数据的值;{case "String":str = sht.GetRow(i).GetCell(j).StringCellValue;//按字符串格式读取单元格数据的值break;case "Numeric":str = sht.GetRow(i).GetCell(j).NumericCellValue.ToString();//按数值格式读取单元格数据的值break;}return str;}private void Btn_SaveSearchResult_Click(object sender, EventArgs e){SaveFileDialog saveFileDialog = new SaveFileDialog();saveFileDialog.Filter = "Excel files (*.xls)|*.xls";saveFileDialog.FilterIndex = 0;saveFileDialog.RestoreDirectory = true;saveFileDialog.CreatePrompt = true;saveFileDialog.Title = "导出Excel文件到";DateTime now = DateTime.Now;saveFileDialog.FileName = "搜索结果" + "-" + DateTime.Now.ToLongDateString().ToString() + "-" + now.Hour.ToString().PadLeft(2, '0') + "时" + now.Minute.ToString().PadLeft(2, '0') + "分" + now.Second.ToString().PadLeft(2, '0') + "秒";saveFileDialog.ShowDialog();this.dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;this.dataGridView1.MultiSelect = false;Stream myStream = saveFileDialog.OpenFile();StreamWriter sw = new StreamWriter(myStream, System.Text.Encoding.GetEncoding("gb2312"));string str = "";try{//写标题     for (int i = 0; i < this.dataGridView1.ColumnCount; i++){if (i > 0){str += "\t";}str += this.dataGridView1.Columns[i].HeaderText;}sw.WriteLine(str);//写内容   for (int j = 0; j < this.dataGridView1.Rows.Count; j++){string tempStr = "";for (int k = 0; k < this.dataGridView1.Columns.Count; k++){if (k > 0){tempStr += "\t";}if (this.dataGridView1.Rows[j].Cells[k].Value != null){tempStr += this.dataGridView1.Rows[j].Cells[k].Value.ToString();}else{continue;}}sw.WriteLine(tempStr);}sw.Close();myStream.Close();if (File.Exists("搜索结果" + "-" + DateTime.Now.ToLongDateString().ToString() + "-" + now.Hour.ToString().PadLeft(2, '0') + ":" + now.Minute.ToString().PadLeft(2, '0') + ":" + now.Second.ToString().PadLeft(2, '0'))){MessageBox.Show("搜索结果保存成功!保存路径与原文件路径相同!", "保存提示");}}catch (Exception ex){MessageBox.Show(ex.ToString());}finally{sw.Close();myStream.Close();}}/// <summary>/// “生产备件清单”按钮的的单击事件,根据匹配成功的行数,删除匹配成功的行数,生成备件清单(匹配成功的表示库房已经有这个备件,则该备件不需要采购,所以将其删除后,剩下的即为备件清单)/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Btn_CreateResultExcel_Click(object sender, EventArgs e){string ResultPath = System.IO.Path.GetDirectoryName(FilePath1) +"\\"+ "备件清单" + "-" + DateTime.Now.ToLongDateString().ToString()+".xlsx";//指定存储的路径           File.Copy(FilePath1, ResultPath, true);//三个参数分别是源文件路径,存储路径,若存储路径有相同文件是否替换int deleteTimes = 0;//记录删除行的次数,因为没删除一行,需要删除的行数索引就变了(减少了1)for (int i = 0; i <= matchRow.Count-1; i++){DeleteRows(ResultPath, (Int32)matchRow[i]+1-deleteTimes);deleteTimes++;}//生成成功提示。if (File.Exists(ResultPath)){MessageBox.Show("备件清单生成成功!保存路径与原文件路径相同!", "保存提示");}else{MessageBox.Show("备件清单生成失败!", "保存提示");}}/// <summary>/// 删除Excel文件中的特定行(上移并覆盖)/// </summary>/// <param name="FilePath">需要删除的Excel文件全路径</param>/// <param name="rowIndex">需要删除的行数索引</param>private void DeleteRows(string FilePath, int rowIndex)//(Excel.Worksheet sheet, int rowIndex){FileStream fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);//必须要选择flieShare方式为ReadWrite,这样就可以在文件被打开的时候读取文件信息。NP.XSSFWorkbook wk = new NP.XSSFWorkbook(fs);//实例化一个.xlsx格式的工作簿NPOI.SS.UserModel.ISheet sht = wk.GetSheetAt(comboBox_sheet1.SelectedIndex);//根据“选择sheet”下拉列表框,获取工作表           sht.ShiftRows(rowIndex, sht.LastRowNum, -1);//将从第rowIndex行到最后一行的数据向上移动一行,即将rowIndex-1行删除了FileStream file = new FileStream(FilePath, FileMode.Create);//实例化一个FileStream文件wk.Write(file);//将file文件流写入wk工作簿file.Close();//关闭文件流}/// <summary>/// 判断matchRow里是否存在当前行索引号(因为文件1中的某一行可能搜索出多个相似结果,经过判断后可以避免重复存入相同的行数到matchRow中,导致生成备件清单时删除错误)/// </summary>/// <param name="i">当前行索引号</param>private void ListAdd(int i){if (!matchRow.Contains(i))//判断集合matchRow中是否包含i{matchRow.Add(i);//如果不包含,则将i添加到matchRow中}else{return;//如果包含,则返回}}private void Located()//(string filePath,){string excelName = FilePath1;//你的excel文件的位置string sheetName = "sheet1";//你的sheet的名字string strStart = "A100";//起始单元格string strEnd = "B200";//结束单元格object missing = Type.Missing;Excel.Application excel = new Excel.Application();Excel.Workbook book = excel.Workbooks.Open(excelName, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing);Excel.Worksheet sheet = (Excel.Worksheet)book.Worksheets[sheetName];excel.Application.Goto(sheet.Range[strStart, strEnd], true);excel.Visible = true;}private void Form1_Load(object sender, EventArgs e){this.Resize += new EventHandler(Form1_Resize);X = this.Width;Y = this.Height;setTag(this);Form1_Resize(new object(), new EventArgs());}//***控制控件大小及文字大小开始***//private float X;private float Y;private void setTag(Control cons){foreach (Control con in cons.Controls){con.Tag = con.Width + ":" + con.Height + ":" + con.Left + ":" + con.Top + ":" + con.Font.Size;if (con.Controls.Count > 0)setTag(con);}}private void setControls(float newx, float newy, Control cons){foreach (Control con in cons.Controls){string[] mytag = con.Tag.ToString().Split(new char[] { ':' });float a = Convert.ToSingle(mytag[0]) * newx;con.Width = (int)a;a = Convert.ToSingle(mytag[1]) * newy;con.Height = (int)(a);a = Convert.ToSingle(mytag[2]) * newx;con.Left = (int)(a);a = Convert.ToSingle(mytag[3]) * newy;con.Top = (int)(a);Single currentSize = Convert.ToSingle(mytag[4]) * Math.Min(newx, newy);con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);if (con.Controls.Count > 0){setControls(newx, newy, con);}}}void Form1_Resize(object sender, EventArgs e){float newx = (this.Width) / X;float newy = this.Height / Y;setControls(newx, newy, this);//this.Text = "窗体尺寸:" + this.Width.ToString() + " " + this.Height.ToString();}//***控制控件大小及文字大小结束***//private void Button1_Click(object sender, EventArgs e){Located();            }private void DataGridView1_DoubleClick(object sender, EventArgs e){//Located();}private void Btn_Help_Click(object sender, EventArgs e){using (Form_Help dlg = new Form_Help()) //Form_Help是窗口类名,确保访问;后面的是构造函数{dlg.ShowDialog();}}private void Btn_Stop_Click(object sender, EventArgs e){flag_SearchStop = true;}}
}

这篇关于C#利用NPOI实现跨Excel数据查找(备件筛选工具)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/616844

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi