程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#讀取Excel的三種方式以及比較,

C#讀取Excel的三種方式以及比較,

編輯:C#入門知識

C#讀取Excel的三種方式以及比較,


(1)OleDB方式

優點:將Excel直接當做數據源處理,通過SQL直接讀取內容,讀取速度較快。

缺點:讀取數據方式不夠靈活,無法直接讀取某一個單元格,只有將整個Sheet頁讀取出來後(結果為Datatable)再在Datatable中根據行列數來獲取指定的值。

           當Excel數據量很大時。會非常占用內存,當內存不夠時會拋出內存溢出的異常。

讀取代碼如下:

   1: public DataTable GetExcelTableByOleDB(string strExcelPath, string tableName)
   2: {
   3:     try
   4:     {
   5:         DataTable dtExcel = new DataTable();
   6:         //數據表
   7:         DataSet ds = new DataSet();
   8:         //獲取文件擴展名
   9:         string strExtension = System.IO.Path.GetExtension(strExcelPath);
  10:         string strFileName = System.IO.Path.GetFileName(strExcelPath);
  11:         //Excel的連接
  12:         OleDbConnection objConn = null;
  13:         switch (strExtension)
  14:         {
  15:             case ".xls":
  16:                 objConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strExcelPath + ";" + "Extended Properties=\"Excel 8.0;HDR=NO;IMEX=1;\"");
  17:                 break;
  18:             case ".xlsx":
  19:                 objConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strExcelPath + ";" + "Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1;\"");
  20:                 break;
  21:             default:
  22:                 objConn = null;
  23:                 break;
  24:         }
  25:         if (objConn == null)
  26:         {
  27:             return null;
  28:         }
  29:         objConn.Open();
  30:         //獲取Excel中所有Sheet表的信息
  31:         //System.Data.DataTable schemaTable = objConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
  32:         //獲取Excel的第一個Sheet表名
  33:         //string tableName = schemaTable.Rows[0][2].ToString().Trim();
  34:         string strSql = "select * from [" + tableName + "]";
  35:         //獲取Excel指定Sheet表中的信息
  36:         OleDbCommand objCmd = new OleDbCommand(strSql, objConn);
  37:         OleDbDataAdapter myData = new OleDbDataAdapter(strSql, objConn);
  38:         myData.Fill(ds, tableName);//填充數據
  39:         objConn.Close();
  40:         //dtExcel即為excel文件中指定表中存儲的信息
  41:         dtExcel = ds.Tables[tableName];
  42:         return dtExcel;
  43:     }
  44:     catch
  45:     {
  46:         return null;
  47:     }
  48: }

下面說明一下連接字符串

        HDR=Yes,這代表第一行是標題,不做為數據使用(但是我在實際使用中,如果第一行存在復雜數值,那麼讀取得到的Datatable列標題會自動設置為F1、F2等方式命名,與實際應用不符,所以當時是通過HDR=No方式將所有內容讀取到Datatable中,然後手動將第一行設置成標題的);IMEX ( IMport EXport mode )設置
IMEX 有三種模式:
0 is Export mode
1 is Import mode
2 is Linked mode (full update capabilities)
我這裡特別要說明的就是 IMEX 參數了,因為不同的模式代表著不同的讀寫行為:
當 IMEX=0 時為“匯出模式”,這個模式開啟的 Excel 檔案只能用來做“寫入”用途。
當 IMEX=1 時為“匯入模式”,這個模式開啟的 Excel 檔案只能用來做“讀取”用途。
當 IMEX=2 時為“鏈接模式”,這個模式開啟的 Excel 檔案可同時支援“讀取”與“寫入”用途。

---------------------------------

另外,讀取Excel2007版本的文件時,版本應該從8.0改為12.0,同時驅動不能再用Jet,而應該用ACE。負責會造成“找不到可安裝的 ISAM”的錯誤。

---------------------------------

在網上還發現采用這種方式存在取出的Sheet表的個數多於實際Excel表中的Sheet表個數的情況,其原因有二:

1. 取出的名稱中,包括了XL命名管理器中的名稱(參見XL2007的公式--命名管理器, 快捷鍵Crtl+F3);

2. 取出的名稱中,包括了FilterDatabase後綴的, 這是XL用來記錄Filter范圍的。

對於第一點比較簡單, 刪除已有命名管理器中的內容即可;第二點處理起來比較麻煩, Filter刪除後這些名稱依然保留著,簡單的做法是新增Sheet然後將原Sheet Copy進去。但實際情況並不能為每個Excel做以上檢查。下面給出了過濾的方案。(此問題我們有驗證過,大家自己驗證一下吧)

   1: //objConn為讀取Excel的鏈接,下面通過過濾來獲取有效的Sheet頁名稱集合
   2:   System.Data.DataTable schemaTable = objConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
   3:   List<string> lstSheetNames = new List<string>();
   4:   for (int i = 0; i < schemaTable.Rows.Count; i++)
   5:   {
   6:       string strSheetName = (string)dtSheetName.Rows[i]["TABLE_NAME"];
   7:       if (strSheetName.Contains("$") && !strSheetName.Replace("'", "").EndsWith("$"))
   8:       {
   9:           //過濾無效SheetName完畢....
  10:           continue;
  11:       }
  12:       if (lstSheetNames != null && !lstSheetNames.Contains(strSheetName))
  13:           lstSheetNames.Add(strSheetName);
  14:   }

因為讀取出來無效SheetName一般情況最後一個字符都不會是$。如果SheetName有一些特殊符號,讀取出來的SheetName會自動加上單引號。比如在Excel中將SheetName編輯成MySheet(1),此時讀取出來的SheetName就為:'MySheet(1)$',所以判斷最後一個字符是不是$之前最好過濾一下單引號。

---------------------------------

(2)Com組件的方式(通過添加 Microsoft.Office.Interop.Excel引用實現)

優點:能夠非常靈活的讀取Excel中的數據,用戶可以靈活的調用各種函數進行處理。

缺點:基於單元格的處理,讀取速度較慢,對於數據量較大的文件最好不要使用此種方式讀取。

           需要添加相應的DLL引用,必須存在此引用才可使用,如果是Web站點部署在IIS上時,還需要服務器機子已安裝了Excel,有時候還需要為配置IIS權限。

讀取代碼如下:

   1: private Stopwatch wath = new Stopwatch();
   2: /// <summary>
   3: /// 使用COM讀取Excel
   4: /// </summary>
   5: /// <param name="excelFilePath">路徑</param>
   6: /// <returns>DataTabel</returns>
   7: public System.Data.DataTable GetExcelData(string excelFilePath)
   8: {
   9:     Excel.Application app = new Excel.Application();
  10:     Excel.Sheets sheets;
  11:     Excel.Workbook workbook = null;
  12:     object oMissiong = System.Reflection.Missing.Value;
  13:     System.Data.DataTable dt = new System.Data.DataTable();
  14:     wath.Start();
  15:     try
  16:     {
  17:         if (app == null)
  18:         {
  19:             return null;
  20:         }
  21:         workbook = app.Workbooks.Open(excelFilePath, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, 
  22:             oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong);
  23:         //將數據讀入到DataTable中——Start   
  24:         sheets = workbook.Worksheets;
  25:         Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);//讀取第一張表
  26:         if (worksheet == null)
  27:             return null;
  28:         string cellContent;
  29:         int iRowCount = worksheet.UsedRange.Rows.Count;
  30:         int iColCount = worksheet.UsedRange.Columns.Count;
  31:         Excel.Range range;
  32:         //負責列頭Start
  33:         DataColumn dc;
  34:         int ColumnID = 1;
  35:         range = (Excel.Range)worksheet.Cells[1, 1];
  36:         while (range.Text.ToString().Trim() != "")
  37:         {
  38:             dc = new DataColumn();
  39:             dc.DataType = System.Type.GetType("System.String");
  40:             dc.ColumnName = range.Text.ToString().Trim();
  41:             dt.Columns.Add(dc);
  42:  
  43:             range = (Excel.Range)worksheet.Cells[1, ++ColumnID];
  44:         }
  45:         //End
  46:         for (int iRow = 2; iRow <= iRowCount; iRow++)
  47:         {
  48:             DataRow dr = dt.NewRow();
  49:             for (int iCol = 1; iCol <= iColCount; iCol++)
  50:             {
  51:                 range = (Excel.Range)worksheet.Cells[iRow, iCol];
  52:                 cellContent = (range.Value2 == null) ? "" : range.Text.ToString();
  53:                     dr[iCol - 1] = cellContent;
  54:             }
  55:             dt.Rows.Add(dr);
  56:         }
  57:         wath.Stop();
  58:         TimeSpan ts = wath.Elapsed;
  59:         //將數據讀入到DataTable中——End
  60:         return dt;
  61:     }
  62:     catch
  63:     {
  64:         return null;
  65:     }
  66:     finally
  67:     {
  68:         workbook.Close(false, oMissiong, oMissiong);
  69:         System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
  70:         workbook = null;
  71:         app.Workbooks.Close();
  72:         app.Quit();
  73:         System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
  74:         app = null;
  75:         GC.Collect();
  76:         GC.WaitForPendingFinalizers();
  77:     }
  78: }
  79: /// <summary>
  80: /// 使用COM,多線程讀取Excel(1 主線程、4 副線程)
  81: /// </summary>
  82: /// <param name="excelFilePath">路徑</param>
  83: /// <returns>DataTabel</returns>
  84: public System.Data.DataTable ThreadReadExcel(string excelFilePath)
  85: {
  86:     Excel.Application app = new Excel.Application();
  87:     Excel.Sheets sheets = null;
  88:     Excel.Workbook workbook = null;
  89:     object oMissiong = System.Reflection.Missing.Value;
  90:     System.Data.DataTable dt = new System.Data.DataTable();
  91:     wath.Start();
  92:     try
  93:     {
  94:         if (app == null)
  95:         {
  96:             return null;
  97:         }
  98:         workbook = app.Workbooks.Open(excelFilePath, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, 
  99:             oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong);
 100:         //將數據讀入到DataTable中——Start   
 101:         sheets = workbook.Worksheets;
 102:         Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);//讀取第一張表
 103:         if (worksheet == null)
 104:             return null;
 105:         string cellContent;
 106:         int iRowCount = worksheet.UsedRange.Rows.Count;
 107:         int iColCount = worksheet.UsedRange.Columns.Count;
 108:         Excel.Range range;
 109:         //負責列頭Start
 110:         DataColumn dc;
 111:         int ColumnID = 1;
 112:         range = (Excel.Range)worksheet.Cells[1, 1];
 113:         while (iColCount >= ColumnID)
 114:         {
 115:             dc = new DataColumn();
 116:             dc.DataType = System.Type.GetType("System.String");
 117:             string strNewColumnName = range.Text.ToString().Trim();
 118:             if (strNewColumnName.Length == 0) strNewColumnName = "_1";
 119:             //判斷列名是否重復
 120:             for (int i = 1; i < ColumnID; i++)
 121:             {
 122:                 if (dt.Columns[i - 1].ColumnName == strNewColumnName)
 123:                     strNewColumnName = strNewColumnName + "_1";
 124:             }
 125:             dc.ColumnName = strNewColumnName;
 126:             dt.Columns.Add(dc);
 127:             range = (Excel.Range)worksheet.Cells[1, ++ColumnID];
 128:         }
 129:         //End
 130:         //數據大於500條,使用多進程進行讀取數據
 131:         if (iRowCount - 1 > 500)
 132:         {
 133:             //開始多線程讀取數據
 134:             //新建線程
 135:             int b2 = (iRowCount - 1) / 10;
 136:             DataTable dt1 = new DataTable("dt1");
 137:             dt1 = dt.Clone();
 138:             SheetOptions sheet1thread = new SheetOptions(worksheet, iColCount, 2, b2 + 1, dt1);
 139:             Thread othread1 = new Thread(new ThreadStart(sheet1thread.SheetToDataTable));
 140:             othread1.Start();
 141:             //阻塞 1 毫秒,保證第一個讀取 dt1
 142:             Thread.Sleep(1);
 143:             DataTable dt2 = new DataTable("dt2");
 144:             dt2 = dt.Clone();
 145:             SheetOptions sheet2thread = new SheetOptions(worksheet, iColCount, b2 + 2, b2 * 2 + 1, dt2);
 146:             Thread othread2 = new Thread(new ThreadStart(sheet2thread.SheetToDataTable));
 147:             othread2.Start();
 148:             DataTable dt3 = new DataTable("dt3");
 149:             dt3 = dt.Clone();
 150:             SheetOptions sheet3thread = new SheetOptions(worksheet, iColCount, b2 * 2 + 2, b2 * 3 + 1, dt3);
 151:             Thread othread3 = new Thread(new ThreadStart(sheet3thread.SheetToDataTable));
 152:             othread3.Start();
 153:             DataTable dt4 = new DataTable("dt4");
 154:             dt4 = dt.Clone();
 155:             SheetOptions sheet4thread = new SheetOptions(worksheet, iColCount, b2 * 3 + 2, b2 * 4 + 1, dt4);
 156:             Thread othread4 = new Thread(new ThreadStart(sheet4thread.SheetToDataTable));
 157:             othread4.Start();
 158:             //主線程讀取剩余數據
 159:             for (int iRow = b2 * 4 + 2; iRow <= iRowCount; iRow++)
 160:             {
 161:                 DataRow dr = dt.NewRow();
 162:                 for (int iCol = 1; iCol <= iColCount; iCol++)
 163:                 {
 164:                     range = (Excel.Range)worksheet.Cells[iRow, iCol];
 165:                     cellContent = (range.Value2 == null) ? "" : range.Text.ToString();
 166:                     dr[iCol - 1] = cellContent;
 167:                 }
 168:                 dt.Rows.Add(dr);
 169:             }
 170:             othread1.Join();
 171:             othread2.Join();
 172:             othread3.Join();
 173:             othread4.Join();
 174:             //將多個線程讀取出來的數據追加至 dt1 後面
 175:             foreach (DataRow dr in dt.Rows)
 176:                 dt1.Rows.Add(dr.ItemArray);
 177:             dt.Clear();
 178:             dt.Dispose();
 179:             foreach (DataRow dr in dt2.Rows)
 180:                 dt1.Rows.Add(dr.ItemArray);
 181:             dt2.Clear();
 182:             dt2.Dispose();
 183:             foreach (DataRow dr in dt3.Rows)
 184:                 dt1.Rows.Add(dr.ItemArray);
 185:             dt3.Clear();
 186:             dt3.Dispose();
 187:             foreach (DataRow dr in dt4.Rows)
 188:                 dt1.Rows.Add(dr.ItemArray);
 189:             dt4.Clear();
 190:             dt4.Dispose();
 191:             return dt1;
 192:         }
 193:         else
 194:         {
 195:             for (int iRow = 2; iRow <= iRowCount; iRow++)
 196:             {
 197:                 DataRow dr = dt.NewRow();
 198:                 for (int iCol = 1; iCol <= iColCount; iCol++)
 199:                 {
 200:                     range = (Excel.Range)worksheet.Cells[iRow, iCol];
 201:                     cellContent = (range.Value2 == null) ? "" : range.Text.ToString();
 202:                     dr[iCol - 1] = cellContent;
 203:                 }
 204:                 dt.Rows.Add(dr);
 205:             }
 206:         }
 207:         wath.Stop();
 208:         TimeSpan ts = wath.Elapsed;
 209:         //將數據讀入到DataTable中——End
 210:         return dt;
 211:     }
 212:     catch
 213:     {
 214:         return null;
 215:     }
 216:     finally
 217:     {
 218:         workbook.Close(false, oMissiong, oMissiong);
 219:         System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
 220:         System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
 221:         workbook = null;
 222:         app.Workbooks.Close();
 223:         app.Quit();
 224:         System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
 225:         app = null;
 226:         GC.Collect();
 227:         GC.WaitForPendingFinalizers();
 228:     }
 229: }

---------------------------------

(3)NPOI方式讀取Excel(此方法未經過測試)

NPOI 是 POI 項目的 .NET 版本。POI是一個開源的Java讀寫Excel、WORD等微軟OLE2組件文檔的項目。使用 NPOI 你就可以在沒有安裝 Office 或者相應環境的機器上對 WORD/EXCEL 文檔進行讀寫。

優點:讀取Excel速度較快,讀取方式操作靈活性

缺點:需要下載相應的插件並添加到系統引用當中。

   1: /// <summary>
   2: /// 將excel中的數據導入到DataTable中
   3: /// </summary>
   4: /// <param name="sheetName">excel工作薄sheet的名稱</param>
   5: /// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param>
   6: /// <returns>返回的DataTable</returns>
   7: public DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn)
   8: {
   9:     ISheet sheet = null;
  10:     DataTable data = new DataTable();
  11:     int startRow = 0;
  12:     try
  13:     {
  14:         fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
  15:         if (fileName.IndexOf(".xlsx") > 0) // 2007版本
  16:             workbook = new XSSFWorkbook(fs);
  17:         else if (fileName.IndexOf(".xls") > 0) // 2003版本
  18:             workbook = new HSSFWorkbook(fs);
  19:         if (sheetName != null)
  20:         {
  21:             sheet = workbook.GetSheet(sheetName);
  22:         }
  23:         else
  24:         {
  25:             sheet = workbook.GetSheetAt(0);
  26:         }
  27:         if (sheet != null)
  28:         {
  29:             IRow firstRow = sheet.GetRow(0);
  30:             int cellCount = firstRow.LastCellNum; //一行最後一個cell的編號 即總的列數
  31:             if (isFirstRowColumn)
  32:             {
  33:                 for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
  34:                 {
  35:                     DataColumn column = new DataColumn(firstRow.GetCell(i).StringCellValue);
  36:                     data.Columns.Add(column);
  37:                 }
  38:                 startRow = sheet.FirstRowNum + 1;
  39:             }
  40:             else
  41:             {
  42:                 startRow = sheet.FirstRowNum;
  43:             }
  44:             //最後一列的標號
  45:             int rowCount = sheet.LastRowNum;
  46:             for (int i = startRow; i <= rowCount; ++i)
  47:             {
  48:                 IRow row = sheet.GetRow(i);
  49:                 if (row == null) continue; //沒有數據的行默認是null       
  50:                 
  51:                 DataRow dataRow = data.NewRow();
  52:                 for (int j = row.FirstCellNum; j < cellCount; ++j)
  53:                 {
  54:                     if (row.GetCell(j) != null) //同理,沒有數據的單元格都默認是null
  55:                         dataRow[j] = row.GetCell(j).ToString();
  56:                 }
  57:                 data.Rows.Add(dataRow);
  58:             }
  59:         }
  60:         return data;
  61:     }
  62:     catch (Exception ex)
  63:     {
  64:         Console.WriteLine("Exception: " + ex.Message);
  65:         return null;
  66:     }
  67: }

部分內容參考http://www.cnblogs.com/Tsong/archive/2013/02/21/2920941.html。特此說明!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved