在應用程序的設計中,常常須要讀取Excel數據或將Excel數據導入轉換到其餘數據載體中,C#讀取Excel的方式有兩種,一種是經過OLEDB方式讀取,另外一種爲經過COM組件方式讀取。近段時間有客戶反映,讀取到程序中的Excel表,出現部分數據丟失的狀況,筆者在此採用的是第一種方式讀取(第二種讀取比較慢,且不易控制),因而檢查代碼還有各類找資料,終於解決了該問題,在此記錄致使丟失的緣由及解決方法。框架
問題的根源與Excel ISAM(Indexed Sequential Access Method,即索引順序存取方法)驅動程序的限制有關,Excel ISAM 驅動程序經過檢查前幾行中實際值肯定一個 Excel 列的類型,而後選擇可以表明其樣本中大部分值的數據類型。也即Excel ISAM查找某列前幾行(默認狀況下是8行),把佔多的類型做爲其處理類型。例如若是數字佔多,那麼其它含有字母等文本的數據項就會置空;相反若是文本居多,純數字的數據項就會被置空。 ide
若Excel爲Excel997-2003版本(後綴爲「.xls」),讀取的驅動爲Jet,鏈接語句以下:spa
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties='Excel 8.0;HDR={1};IMEX={2}'"
若Excel爲Excel 2007及以後版本(後綴爲「.xlsx」),讀取的驅動爲ACE,鏈接語句以下:設計
「Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0;HDR={1};IMEX={2}'」
其中:excel
當 IMEX=0 時爲「匯出模式」,這個模式開啓的 Excel 檔案只能用來作「寫入」用途;code
當 IMEX=1 時爲「匯入模式」,這個模式開啓的 Excel 檔案只能用來作「讀取」用途;blog
當 IMEX=2 時爲「連接模式」,這個模式開啓的 Excel 檔案可同時支援「讀取」與「寫入」用途;索引
當 HDR=Yes,這表明第一行是標題;string
當 HDR=No,第一行做爲數據內容。it
當咱們設置IMEX=1時將強制混合數據轉換爲文本,但僅僅這種設置並不可靠,IMEX=1只確保在某列前8行數據至少有一個是文本項的時候才起做用,它只是把查找前8行數據中數據類型佔優選擇的行爲做了略微的改變。例如某列前8行數據全爲純數字,那麼它仍然以數字類型做爲該列的數據類型,隨後行裏的含有文本的數據仍然變空。
設置IMEX=1,修改註冊表值TypeGuessRows(TypeGuessRows 值決定了ISAM 驅動程序從前幾條數據採樣肯定數據類型,默認爲「8」)爲0,程序就會默認行數爲最大。
對於修改註冊表不熟悉的讀者,具體步驟以下:
開始菜單,輸入「Regedit」,打開註冊表,找到「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\」項,按下「Ctrl+F」鍵,輸入「TypeGuessRows」選擇「值」項,以下圖所示。
點擊【查找下一個】按鈕,查到找結果以下圖所示,筆者Office版本爲Office 2016 64bit。
右鍵該項,修改「TypeGuessRows」的值爲「0」便可,以下圖所示。
在此貼出C#讀取Excel表到DataTable的方法代碼:
public static DataTable GetExcelTableByOleDb(string excelPath, string tableName) { try { DataTable excelTable = new DataTable(); //數據表 DataSet ds = new DataSet(); //獲取文件擴展名 //Excel的鏈接 OleDbConnection objConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + excelPath + ";Extended Properties='Excel 12.0;HDR=Yes;IMEX=1;'");
if (objConn == null) { return null; } objConn.Open(); string strSql = "select * from [" + tableName + "]";//獲取Excel指定Sheet表中的信息 OleDbDataAdapter myData = new OleDbDataAdapter(strSql, objConn); myData.Fill(ds, tableName);//填充數據 objConn.Close(); //dtExcel即爲excel文件中指定表中存儲的信息 excelTable = ds.Tables[tableName]; return excelTable; } catch { return null; } }
至此,不完美的解決了該問題,由於兩種方法各有優缺點,受制於框架,這是沒法避免的,後邊有時間會寫一篇經過開源庫NPOI讀取及建立Excel(不須要安裝Office),以此完全解決限制問題。若是該篇博文對你有幫助,但願點個關注支持下。