C#讀取Excel的三種方式以及比較
優點:將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: }
相關推薦
no