C#完全解決Oledb鏈接Excel數據類型不統一的問題

在使用Microsoft.Jet.OLEDB.4.0鏈接Excel,進行讀取數據,相對使用傳統的COM來讀取數據,效率是很高的。但相對傳統COM操做Excel來講,及存在數據類型轉換的問題。

由於使用OLEDB鏈接Excel讀取數據時,須要肯定數據的類型。默認狀況使用鏈接字符串: ide

1. string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + excelFile + ";Extended Properties='Excel 8.0;'";

 使用上面的鏈接字符串鏈接Excel時,可能會遇到數據類型不一致的問題。所謂數據類型不一致,是指同一列裏面數據類型可能出現多種,如浮點數、字符串、日期等;當出現此類狀況時,讀取出來的數據就爲空,甚至會報錯,如「非法的日期格式」等異常。出現這種問題,咱們你們都會想到把數據所有都按字符數據來讀取,可是按什麼數據類型來讀取不是咱們能控制的,是OLEDB控制的,至少暫時我尚未找到能控制輸出數據類型的方法。由於我當初也嘗試使用convert,cast函數對輸出的列進行類型轉換,但oledb鏈接Excel時,使用的SQL不支持這些函數。所以只能從其餘角度來解決該問題。我也在網上搜索了不少解決方法,最全面的解決方法是:http://www.douban.com/note/18510346/。下面列出了網上出現解決該問題方法的比較: 函數

 

解決方案 說明 缺點
COM 使用Excel COM接口訪問Excel 非託管、不容易釋放資源、效率低下
鏈接字符串添加IMEX=1 構造的鏈接字符串,如:
1. string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + excelFile + ";Extended Properties='Excel 8.0;HDR=YES;IMEX=1'";
其中HDR表示是否將Sheet頁的第一行做爲字段名,「YES」表明是,「NO」表明不是,當爲YES時,將把SHEET頁的第一行做爲字段名,數據從第二行開始,而若是是NO時,字段名就是要SHEET的列名,如A,B,C等,數據就從第一行開始取;IMEX是用來告訴驅動程序,使用Excel文件的模式,其值有0、一、2三種,分別表明導出、導入、混合模式。當咱們設置IMEX=1時將強制混合數據轉換爲文本,但僅僅這種設置並不可靠,IMEX=1只確保在某列前8行數據至少有一個是文本項的時候才起做用,它只是把查找前8行數據中數據類型佔優選擇的行爲做了略微的改變。例如某列前8行數據全爲純數字,那麼它仍然以數字類型做爲該列的數據類型,隨後行裏的含有文本的數據仍然變空。 (摘至:http://www.douban.com/note/18510346/)。
只根據前8行數據判斷是否使用字符類型
IMEX=1與註冊表值TypeGuessRows配合使用 TypeGuessRows 值決定了ISAM 驅動程序從前幾條數據採樣肯定數據類型,默認爲「8」。能夠經過修改「HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Jet/4.0/Engines/Excel」下的該註冊表值來更改採樣行數。可是這種改進仍是沒有根本上解決問題,即便咱們把IMEX設爲「1」, TypeGuessRows設得再大,例如1000,假設數據表有1001行,某列前1000行全爲純數字,該列的第1001行又是一個文本,ISAM驅動的這種機制仍是讓這列的數據變成空。 (摘至:http://www.douban.com/note/18510346/)。 修改註冊表不方便,並且沒法事先判讀sheet有多少行,所以仍是受行數限制。
將Excel先轉換成csv純文本格式

(1)在讀取Excel的.xls類型的文本數據以前,先將其轉換爲.csv格式,在Excel中直接另存爲這種格式就能夠達到轉換的目的。CSV文件又稱爲逗號分隔的文件,是一種純文本文件,它以「,」分隔數據列。 spa

須要指出的是,CSV文件也能夠用Ole DB或ODBC的方式讀取,可是若是採用這些方式讀取其數據又會回到丟失數據的老路上,ISAM機制一樣會發揮做用。 .net

(2)採用普通的讀取文本文件的方法打開文件,讀取第一行,用「,」做爲分隔符得到各字段名,在DataTable中建立對應的各字段,字段的類型能夠統一建立成「String」。 excel

(3)逐行讀取數據行, 用「,」做爲分隔符得到某行各列的數據並填入DataTable相應的字段中。 orm

簡要代碼: blog

01. String line; 
02. String [] split = null; 
03. DataTable table=new DataTable("auto"); 
04. DataRow row=null; 
05. StreamReader sr=newStreamReader("c:/auto.csv",System.Text.Encoding.Default); 
06. //建立與數據源對應的數據列 
07. line = sr.ReadLine(); 
08. split=line.Split(','); 
09. foreach(String colname in split){ 
10.   table.Columns.Add(colname,System.Type.GetType("System.String")); 
11.
12. //將數據填入數據表 
13. int j=0; 
14. while((line=sr.ReadLine())!=null){ 
15.   j=0; 
16.   row = table.NewRow(); 
17.   split=line.Split(','); 
18.   foreach(String colname in split){ 
19.       row[j]=colname; 
20.       j++;
21.    
22.   table.Rows.Add(row);
23.
24. sr.Close(); 
25. //顯示數據 
26. dataGrid1.DataSource=table.DefaultView; 
27. dataGrid1.DataBind();
(摘至:http://www.douban.com/note/18510346/)。
須要事先將excel轉換成csv文件

 

這裏提供一個更加方便的辦法,不過前提是第一行必須是做爲字段名或者第一行的數據類型就爲字符型。這樣一說,你們就明白了。首先修改鏈接字符串爲: 接口

//2003(Microsoft.Jet.Oledb.4.0)
string strConn = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties='Excel 8.0;HDR=Yes;IMEX=1;'", excelFilePath);
資源

//2010(Microsoft.ACE.OLEDB.12.0)
string strConn = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 8.0;HDR=Yes;IMEX=1;'", excelFilePath);
字符串



這裏將HDR設爲NO,由於我就是將第一行作爲數據讀取,而IMEX=1就表示根據前8行判斷列的數據類型,若是有字符型數據,那麼就強制混合數據轉換爲文本。這裏就明白爲何要保證第一行爲字符型的緣由了。能將列的數據類型強制設爲字符型,那麼列中出現什麼類型的數據都不怕了。須要作的工做就是,在獲取完數據後,將字段名從新設置,並刪除第一條記錄便可。代碼以下:

01. DataTable dt = new DataTable();
02.   
03. using(OleDbCommand cmd = new OleDbCommand()){
04.     cmd.Connection = conn;
05.     cmd.CommandType = CommandType.Text;
06.     cmd.CommandTimeout = 6;
07.     cmd.CommandText = string.Format("select * from [{0}$]", sheetName);
08.   
09.     OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
10.     adapter.Fill(dt);
11. }
12.   
13. if (dt.Rows.Count > 0) {
14.     DataRow dr = dt.Rows[0];
15.   
16.     for (int col = 0; col < dt.Columns.Count; col++) {
17.         dt.Columns[col].ColumnName = dr[col].ToString();
18.     }
19.   
20.     dt.Rows[0].Delete();
21.     dt.AcceptChanges();
22. }
相關文章
相關標籤/搜索