打开 导入Excel文件 (异步)
Posted x666066
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打开 导入Excel文件 (异步)相关的知识,希望对你有一定的参考价值。
引用 类库:
using NPOI.SS.UserModel;
using System.Threading;
object lockObject = new object();
int CurrentSheetIndex = 0;//当前选择的Sheet;
DateTime dateStart = DateTime.Now;//开始导入的时间
ISheet Currentsheet = null;//当前的Sheet;
int Step = 3000;//每个线程处理的行数
int MaxThreadQty = 6;//取大子线程数
int currentThreadQty = 0;//当前的子线程数
int ShowMessageCount = 50;//多少行才提示
int CurrentValue = 0;
DataTable dtPreview = null;//预览的数据
string resultByExcelToDB = "";//导入batch检查长度
Dictionary<string, int> Columns = new Dictionary<string, int>();//记录字段在当前表格中的顺序
Thread ttMain;
Thread tt;
/// <summary> /// 选择文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnOpenFile_Click(object sender, EventArgs e) OpenFileDialog open = new OpenFileDialog(); open.Filter = "Excel File|*.xls;*.xlsx"; if (open.ShowDialog() == DialogResult.OK) this.txtPath.Text = open.FileName; string s = txtPath.Text; //this.txtTableName.Text = s.Substring(s.LastIndexOf(‘\\‘) + 1).Replace(".xls", ""); try //尝试新的读方法 IWorkbook hssfworkbook; using (FileStream file = new FileStream(open.FileName, FileMode.Open, FileAccess.Read)) hssfworkbook = WorkbookFactory.Create(file); file.Dispose(); ISheet sheet = hssfworkbook.GetSheetAt(0); comSheet.Items.Clear(); for (int i = 0; i < hssfworkbook.NumberOfSheets; i++) comSheet.Items.Add(hssfworkbook.GetSheetName(i)); comSheet.SelectedIndex = 0; catch (Exception ee) MessageBox.Show(ee.Message); /// <summary> /// Sheet 选择切换事件,加载预览数据,这里只加载1千行,防止太多,加载太慢 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void comSheet_SelectedIndexChanged(object sender, EventArgs e) CurrentSheetIndex = comSheet.SelectedIndex; backgroundWorker1.RunWorkerAsync(); labMsg.Text = "加载数据中,请耐心等待"; /// <summary> /// 读取excel 到DataTable 中 /// /// </summary> /// <param name="strFilePath">excel文档路径 这里是绝对路径,如果不是绝对路径</param> /// <param name="StartRowIndex">开始的行下标(包括标题行),起始值是0</param> /// <param name="SheetIndex">Shoee的下标,默认是0起始值是0</param> /// <param name="returnRowCount">返回指定行数的数据,主要是为了获取预览数据,0表示返回所有数据,否则就是指定的行数</param> /// <param name="FrisRowToColumn">第一行是否当作转换成数据表的列</param> /// <returns></returns> public DataTable Import(string strFilePath, int StartRowIndex, int SheetIndex = 0, int returnRowCount = 0, bool FrisRowToColumn = true) Columns = new Dictionary<string, int>();//初始化 DataTable dt = new DataTable(); IWorkbook hssfworkbook; using (FileStream file = new FileStream(strFilePath, FileMode.Open, FileAccess.Read)) hssfworkbook = WorkbookFactory.Create(file); Currentsheet = hssfworkbook.GetSheetAt(SheetIndex); //progressBar.Maximum = Currntsheet.LastRowNum; //labMsg.Text = Currntsheet.LastRowNum.ToString(); if (Currentsheet.LastRowNum < Step) ShowMessageCount = 50; else if (Currentsheet.LastRowNum > Step && Currentsheet.LastRowNum < 10000) ShowMessageCount = 100; else ShowMessageCount = 1000; System.Collections.IEnumerator rows = Currentsheet.GetRowEnumerator(); IRow headerRow = Currentsheet.GetRow(StartRowIndex); if (headerRow == null) return dt;//这里为什么读不到数据,还要再看一下 int cellCount = headerRow.LastCellNum; if (FrisRowToColumn)//第一行转换成字段 for (int j = 0; j < cellCount; j++) ICell cell = headerRow.GetCell(j); if (cell != null) Columns[cell.ToString().Trim()] = j; dt.Columns.Add(cell.ToString()); else dt.Columns.Add("F" + j); #region 验证表头是否正确 try int ii = Columns["Material"]; // ii = Columns["Material Description"]; ii = Columns["Material Description"]; ii = Columns["Batch"]; ii = Columns["Storage Location"]; ii = Columns["Movement type"]; ii = Columns["Order"]; ii = Columns["Posting Date"]; ii = Columns["Purchase order"]; ii = Columns["Quantity"]; ii = Columns["Material Doc.Item"]; ii = Columns["Material Document"]; catch MessageBox.Show("请将表头设置成正确的值"); #endregion StartRowIndex++; else for (int j = 0; j < cellCount; j++) dt.Columns.Add("F" + j); int rowCount = 0; for (int i = StartRowIndex; i <= Currentsheet.LastRowNum; i++) IRow row = Currentsheet.GetRow(i); DataRow dataRow = dt.NewRow(); for (int j = row.FirstCellNum; j < cellCount; j++) if (row.GetCell(j) != null) dataRow[j] = row.GetCell(j).ToString(); dt.Rows.Add(dataRow); //如果已经到达要求的行数,返回 rowCount++; if (returnRowCount > 0 && rowCount >= returnRowCount) break; return dt; /// <summary> /// 导入按钮 执行删除导入到数据库里 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btndeleteImport_Click(object sender, EventArgs e) if (!string.IsNullOrEmpty(txtPath.Text.Trim())) try Step = Convert.ToInt32(txt_Step.Text.Trim()); MaxThreadQty = Convert.ToInt32(txt_MaxThredQty.Text.Trim()); catch (Exception ee) MessageBox.Show(ee.Message); return; //初始化各数据 progressBar.Value = 0; labMsg.Text = ""; dateStart = DateTime.Now; CurrentValue = 0; currentThreadQty = 0; btndeleteImport.Enabled = false; btnCompute.Enabled = false; btnOpenFile.Enabled = false; btndel.Enabled = false; comSheet.Enabled = false; ttMain = new Thread(() => int taskCount; try taskCount = Currentsheet.LastRowNum / Step;//整除运算 catch (Exception) MessageBox.Show("请耐心等待,数据加载完成再导入!"); return; for (int i = 0; i < taskCount + 1; i++) int index = i; tt = new Thread(() => DoAsyncImport(index * Step, index * Step + Step); ); tt.IsBackground = true; tt.Start(); currentThreadQty++; Thread.Sleep(100);//防止线程扎堆 while (currentThreadQty >= MaxThreadQty) Thread.Sleep(200); ); ttMain.Start(); else MessageBox.Show("请选择Excel表格!"); /// <summary> /// 执行异步导入动作 /// </summary> private void DoAsyncImport(int startIndex, int endIndex) if (endIndex > Currentsheet.LastRowNum) endIndex = Currentsheet.LastRowNum + 1; for (int i = startIndex; i < endIndex; i++) IRow row = Currentsheet.GetRow(i); if (i == 0 || row == null)//第一行是表头,不处理 continue; DoInsertDB("WMTL_ITEM_BATCH", row); //lock (lockObject) // CurrentValue++; // //减少显示信息的次数 if (CurrentValue % ShowMessageCount == 0 || CurrentValue == Currentsheet.LastRowNum) if (this.progressBar.InvokeRequired) this.progressBar.BeginInvoke(new SetMessageCallback(SetMesage), new object[] CurrentValue, startIndex + "/" + endIndex ); else SetMesage(CurrentValue, startIndex + "/" + endIndex); currentThreadQty--; /// <summary> /// 处理单行数据,将数据插入到数据库中 /// </summary> /// <param name="Table"></param> /// <param name="row"></param> private void DoInsertDB(string Table, IRow row) string PostingDate = ""; if (row.GetCell(Columns["Posting Date"]) != null) try if (row.GetCell(Columns["Posting Date"]).CellType == CellType.STRING) PostingDate = DateTime.ParseExact(row.GetCell(Columns["Posting Date"]).StringCellValue, "dd.MM.yyyy", System.Globalization.CultureInfo.GetCultureInfo("en-US")).ToString("yyyy-MM-dd"); // PostingDate = Convert.ToDateTime(row.GetCell(Columns["Posting Date"]).StringCellValue).ToString("yyyy-MM-dd"); else string strDate = DateTime.FromOADate(row.GetCell(Columns["Posting Date"]).NumericCellValue).ToString("d"); PostingDate = Convert.ToDateTime(strDate).ToString("yyyy-MM-dd"); catch (Exception) MessageBox.Show(row.GetCell(Columns["Posting Date"]).NumericCellValue + "日期格式不合法"); string MATERIAL = Convert.ToString(row.GetCell(Columns["Material"])); string MATERIAL_DESC = Convert.ToString(row.GetCell(Columns["Material Description"])); string BATCH = Convert.ToString(row.GetCell(Columns["Batch"])); //对batch 判断 如果开头为“00”,则为不合法数据 王万香2019年7月8日12:33:02 string val = BATCH.Substring(0, 2); if (val == "00") resultByExcelToDB += "第" + row.RowNum + "行数据"+ BATCH + "常度不合法!\n"; return; string STORAGE_LOCATION = Convert.ToString(row.GetCell(Columns["Storage Location"])); string MOVEMENT_TYPE = Convert.ToString(row.GetCell(Columns["Movement type"])); string ORDER_PO = Convert.ToString(row.GetCell(Columns["Order"])); string PURCHASE_ORDER = Convert.ToString(row.GetCell(Columns["Purchase order"])); string MATERIAL_DOC = Convert.ToString(row.GetCell(Columns["Material Document"])); string MATERIAL_DOC_ITEM = Convert.ToString(row.GetCell(Columns["Material Doc.Item"])); int QUANTITY = Convert.ToInt32( row.GetCell(Columns["Quantity"]).NumericCellValue); string POSTING_DATE = PostingDate; string USER_ID = FrmLogin.user_ID; string IMPORT_TIME = DateTime.Now.ToString("yyyy-MM-dd:HH:mm:ss"); string sqlstr = " INSERT INTO " + Table + " SELECT ‘" + MATERIAL + "‘,‘" + MATERIAL_DESC + "‘,‘" + BATCH + "‘,‘" + STORAGE_LOCATION + "‘,‘" + MOVEMENT_TYPE + "‘,‘" + ORDER_PO + "‘,‘" + PURCHASE_ORDER + "‘,‘" + MATERIAL_DOC + "‘,‘" + MATERIAL_DOC_ITEM + "‘," + QUANTITY+",‘"+ POSTING_DATE + "‘,‘" + USER_ID + "‘,‘" + IMPORT_TIME + "‘"; SqlServerHelper.ExeSql(sqlstr); //sqlstr += " WHERE NOT EXISTS(SELECT ‘X‘ FROM " + Table + " T WHERE T.BATCH=‘" + BATCH + "‘)"; //if (!SqlServerHelper.ExeSql(sqlstr)) // // sqlstr = " UPDATE " + Table + " SET MATERIAL=‘" + MATERIAL + "‘,MATERIAL_DESC=‘" + MATERIAL_DESC + "‘,BATCH=‘" + BATCH + "‘,MOVEMENT_TYPE=‘" + MOVEMENT_TYPE + "‘,ORDER_PO=‘" + ORDER_PO + // "‘,PURCHASE_ORDER=‘" + PURCHASE_ORDER + "‘,MATERIAL_DOC=‘" + MATERIAL_DOC + "‘,POSTING_DATE=‘" + POSTING_DATE + "‘,QUANTITY=" + QUANTITY + ",USER_ID=‘" + USER_ID + "‘,IMPORT_TIME=‘" + IMPORT_TIME + // "‘,STORAGE_LOCATION=‘"+ STORAGE_LOCATION + "‘,MATERIAL_DOC_ITEM=‘"+ MATERIAL_DOC_ITEM + "‘ WHERE BATCH=‘" + BATCH + "‘"; // /// <summary> /// 执行插入数据库的的动作,这个方法不使用了 /// </summary> // private void DoInsertDB(IRow row) // // string sqlstr = @"INSERT INTO WMTL_ITEM_BATCH( // MATERIAL,MATERIAL_DESC,BATCH,MOVEMENT_TYPE,ORDER_PO,PURCHASE_ORDER, // COST_CENTER,MATERIAL_DOC,POSTING_DATE,DOCUMENT_DATE) //VALUES(‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘,‘6‘,‘7‘,‘8‘,‘9‘)"; // //for (int j = row.FirstCellNum; j < row.LastCellNum; j++) // // // // // int ii = Columns["Material"]; // ii = Columns["Material Description"]; // ii = Columns["Batch"]; // ii = Columns["Movement type"]; // ii = Columns["Order"]; // ii = Columns["Purchase order"]; // //ii = Columns["Cost Center"]; // ii = Columns["Material Document"]; // //将两个时间的格式转换 // string PostingDate = ""; // if (row.GetCell(Columns["Posting Date"]) != null) // // if (row.GetCell(Columns["Posting Date"]).CellType == CellType.STRING) // // PostingDate = DateTime.ParseExact(row.GetCell(Columns["Posting Date"]).StringCellValue, "dd.MM.yyyy", System.Globalization.CultureInfo.GetCultureInfo("en-US")).ToString("yyyy-MM-dd"); // // PostingDate = Convert.ToDateTime(row.GetCell(Columns["Posting Date"]).StringCellValue).ToString("yyyy-MM-dd"); // // else // // string strDate = DateTime.FromOADate(row.GetCell(Columns["Posting Date"]).NumericCellValue).ToString("d"); // PostingDate = Convert.ToDateTime(strDate).ToString("yyyy-MM-dd"); // // // string DocumentDate = ""; // //if (row.GetCell(Columns["Document Date"]) != null) // // // // string strDate = DateTime.FromOADate(row.GetCell(Columns["Document Date"]).NumericCellValue).ToString("d"); // // DocumentDate = Convert.ToDateTime(strDate).ToString("yyyy-MM-dd"); // // // sqlstr = string.Format(sqlstr, row.GetCell(Columns["Material"]), row.GetCell(Columns["Material Description"]), row.GetCell(Columns["Batch"]), // row.GetCell(Columns["Movement type"]), row.GetCell(Columns["Order"]), // row.GetCell(Columns["Purchase order"]), "", // row.GetCell(Columns["Material Document"]), PostingDate, DocumentDate); // SqlServerHelper.ExeSql(sqlstr); // delegate void SetMessageCallback(int value, string message); private void SetMesage(int value, string message) this.progressBar.Value = CurrentValue; TimeSpan ts = DateTime.Now.Subtract(dateStart); this.labMsg.Text = CurrentValue + "/" + Currentsheet.LastRowNum + " 用时:" + ts.Minutes + "分" + ts.Seconds + "秒"; /// textBox1.Text = this.labMsg.Text + "\r\n" + textBox1.Text; if (CurrentValue == Currentsheet.LastRowNum) btndeleteImport.Enabled = true; btnCompute.Enabled = true; btnOpenFile.Enabled = true; btndel.Enabled = true; comSheet.Enabled = true; MessageBox.Show("导入完成"); if (resultByExcelToDB!=null) MessageBox.Show(resultByExcelToDB,"提示");
以上是关于打开 导入Excel文件 (异步)的主要内容,如果未能解决你的问题,请参考以下文章
C# 自己写的Winform程序批量导入Excel文件到Oracle数据库的过程中,程序运行会很慢!而且Winform窗体会卡