之前基於 .NET 開發的程序,我通常都是使用NPOI操做Excel文件,html
由於個人程序讀取的是另一個成品WMS導出的Excel文件(至於爲何不直接從數據庫獲取該WMS導出到Excel的數據,此中緣由,一言難盡!),在使用NPOI讀取Excel的時候,提示錯誤:sql
Initialisation of record 0x203(NumberRecord) left 4 bytes remaining still to be read.
數據庫
StackOverFlow一個高贊答案就是升級NPOI版本,或使用Office Excel將Excel文件另存爲
,保存爲新的Excel文件再使用NPOI讀取該Excel文件。c#
雖已使用最新的NPOI,可是依舊出現該錯誤,讓用戶另存爲
不合適,可是我又還沒有找到一個簡單有效快速的處理方法。服務器
考慮到服務器上已經安裝的Office套件,因此使用Com組件的方法操做Excel文件,可是讀取速度較慢。ide
最終嘗試使用ADO .NET 中的OleDbConnection類讀取Excel文件,讀取速度,且相對方便,簡單記錄以下。測試
在.NET程序中須要操做Excel文件,不論xls格式仍是xlsx格式都是可使用NPOI.net
Nuget獲取該擴展:excel
PM> Install-Package NPOI -Version 2.5.2
簡單的一個示例,讀取用戶上傳的Excel文件:code
/// <summary> /// 讀取Excel導入DataTable /// </summary> /// <param name="filepath">導入的文件路徑(包括文件名)</ param> /// <param name="sheetName">工做表名稱</param> /// <param name="isFirstRowColumn">第一行是不是DataTable的列 名</param> /// <returns>DataTable</returns> public static DataTable ExcelToDataTable(string filePath,string sheetName,bool isFirstRowColumn) { DataTable data = new DataTable(); FileStream fs; int startRow = 0; using (fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { try { IWorkbook workbook = filePath.Contains(".xlsx") ? (IWorkbook)new XSSFWorkbook(fs) :newHSSFWorkbook(fs);//xlsx使用XSSFWorkbook, xls使用HSSFWorkbokk ISheet sheet = workbook.GetSheet(sheetName) ?? workbook.GetSheetAt(0);//若是沒有找到指sheetName 對應的sheet,則嘗試獲取第一個sheet if (sheet != null) { IRow firstrow = sheet.GetRow(0);//第一行 int firstCellNum = firstrow.FirstCellNum;// 行第一個cell的編號,從0開始 int lastCellNum = firstrow.LastCellNum; // 行最後一個cell的編號 即總的列數,(不忽略中間某 列空格) if (isFirstRowColumn)//若是第一行是表格列頭 { for (int i = firstCellNum; i < lastCellNum; i++) { ICell cell = firstrow.GetCell(i); if (cell != null) { string cellValue = cell.StringCellValue; if (cellValue != null) { DataColumn column = new DataColumn(cellValue); data.Columns.Add(column); } } } startRow = sheet.FirstRowNum + 1; } else { startRow = sheet.FirstRowNum; } //讀數據行 int rowCont = sheet.LastRowNum; for (int i = startRow; i <=rowCont; i++) { IRow row = sheet.GetRow(i); DataRow dataRow = data.NewRow(); //判斷須要讀取的最後一行 if (row != null && (row.GetCell(row.FirstCellNum) != null && row.GetCel (rowFirstCellNum).ToString() != "合計") ) { for (int j = row.FirstCellNum; j < lastCellNum; j++) { dataRow[j] = row.GetCell(j).ToString(); } data.Rows.Add(dataRow); } else { break; } } } return data; } catch (Exception ex) { Debug.WriteLine("Exception: " + ex.Message); return null; } finally { fs.Close(); fs.Dispose(); } } }
讀取到Excel表格中的數據到DataTable 中,可使用SqlBulkCopy
批量插入的方式將DataTable數據存儲到數據庫表中,關於ADO .NET 針對SQL Server的批量插入的各類方法以及比較,能夠參考文末給出的參考鏈接
簡單示例以下:
/// <summary> /// 使用SqlBulkCopy將DataTable中的數據批量插入數據庫中 /// 注意:DataTable中的列須要與數據庫表中的列徹底一致。 /// </summary> /// <param name="conStr">數據庫鏈接串</param> /// <param name="dbTableName">數據庫中對應的表名</param> /// <param name="dtData">數據集</param> public static void SqlBulkCopyInsert(string dbTableName, DataTable dataTable) { using (SqlBulkCopy sqlRevdBulkCopy = new SqlBulkCopy(connStr))//引用SqlBulkCopy { sqlRevdBulkCopy.DestinationTableName = dbTableName;//數據庫中對應的表名 sqlRevdBulkCopy.NotifyAfter = dataTable.Rows.Count;//有幾行數據 sqlRevdBulkCopy.WriteToServer(dataTable);//數據導入數據庫 sqlRevdBulkCopy.Close();//關閉鏈接 } }
使用ADO .NET 中的OleDbConnection類鏈接查詢。簡單示例以下:
/// <summary> /// 讀取Excel返回DataTable /// </summary> /// <param name="filePath">Excel文件路徑</param> /// <param name="tableName">Excel文件中Sheet名稱</param> /// <returns></returns> public static DataSet ExcelToDataSet(string filePath, string tableName) { //獲取文件擴展名 string strExtension = System.IO.Path.GetExtension(filePath); OleDbConnection myConn = null; switch (strExtension) { case ".xls": myConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";" + "Extended Properties=\"Excel 8.0;HDR=yes;IMEX=1;\""); break; case ".xlsx": myConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";" + "Extended Properties=\"Excel 12.0;HDR=yes;IMEX=1;\""); //此鏈接能夠操做.xls與.xlsx文件 (支持Excel2003 和 Excel2007 的鏈接字符串) //"HDR=yes;"是說Excel文件的第一行是列名而不是數,"HDR=No;"正好與前面的相反。"IMEX=1 "若是列中的數據類型不一致,使用"IMEX=1"可必免數據類型衝突。 break; default: myConn = null; break; } if (myConn == null) { return null; } string strCom = " SELECT * FROM [" + tableName + "$]"; myConn.Open(); //獲取Excel指定Sheet表中的信息 OleDbDataAdapter myCommand = new OleDbDataAdapter(strCom, myConn); DataSet ds; ds = new DataSet(); myCommand.Fill(ds, tableName); myConn.Close(); return ds.Tables[0]; }
使用OleDbConnection在本地測試沒有問題,在發佈部署在服務器後出現了一個異常:
未在本地計算機上註冊「Microsoft.Jet.OLEDB.4.0」提供程序
解決方法:IIS-->應用程序池-->選中部署的項目右鍵-->高級設置-->啓用32位應用程序-->True