Excel讀入dataset資料丟失的問題

2021-04-18 16:29:41 字數 3983 閱讀 3433

1 引言   在應用程式的設計中,經常需要讀取excel資料或將excel資料匯入轉換到其他資料載體中,例如將excel資料通過應用程式匯入sql sever等資料庫中以備使用。筆者在開發「汽車產業鏈asp協同商務平台」中遇到了類似需求。某汽車整車生產企業需要將其車輛發車資訊發布到汽車產業鏈平台上去,其資料為內部erp系統生成的excel資料表,使用者首先將該資料表上傳至汽車產業鏈平台,平台將此excel資料讀取匯入到平台內部的sql sever資料庫中,以供其它應用使用。汽車產業鏈平台的開發使用的開發工具為vs.net,使用的語言是c#,在開發的過程中發現使用microsoft.jet.oledb.4.0讀取資料會出現當某一字段內分別含有文字和數字的混合資料時,某一型別的資料會產生丟失。本文就對此問題產生的根源進行了分析並給出了相應的解決方法。      2 問題描述   excel是microsoft公司的電子**處理軟體,在現代辦公及企業資訊化的應用中使用非常廣泛,正因如此,在程式設計中我們經常要通過訪問excel檔案來獲得資料,但excel檔案不是標準資料庫[1]。   asp.net也是microsoft公司的產品,作為.net framework框架中的乙個重要組成部分,其主要用於web設計。我們在.net中訪問讀取excel資料時一般採用microsoft.jet.oledb.4.0[2]。現以讀取乙個excel檔案auto.xls中sheet1工作表為例,工作表的內容如表1所示。   表1 sheet1表的資料內容   現將該錶的資料內容讀取並顯示到到datagrid中,簡化的**如下:   string connstr = " provider = microsoft.jet.oledb.4.0; datasource=c:/auto.xls;extended properties='excel 8.0;hdr=yes';";   oledbconnection conn=new oledbconnection(connstr);   conn.open();   string sql="select * from [sheet1$]";   oledbdataadapter da=new oledbdataadapter(sql,connstr);   dataset ds=new dataset();   da.fill(ds);   datagrid1.datasource=ds;   datagrid1.databind();   conn.close();   但是執行以上**的結果並不是期望的,它將顯示為表2所示的內容。可以發現第乙個欄位中為「1042」的兩個資料項變為空。   表2 datagrid1所顯示的資料內容   有程式設計人員將以上**oledbconnection連線字串中的extended properties一項作了如下改動,extended properties='excel 8.0;hdr=no;imex=1』,認為可以解決此問題。由於在開發「汽車產業鏈協同商務平台」中碰到過類似問題,作了大量的測試後發現,新增imex=1後並未實質上解決此問題。表現為:如果某字段前8條記錄中全部為純數字的話,那麼在該字段隨後的記錄中含有字母或漢字的項將仍然變為空,但是如果該字段前8條記錄中有一條不為純數字,將能得到預期想要的結果。      3 問題分析   產生這種問題的根源與excel isam[3](indexed sequential access method,即索引順序訪問方法)驅動程式的限制有關,excel isam 驅動程式通過檢查前幾行中實際值確定乙個 excel 列的型別,然後選擇能夠代表其樣本中大部分值的資料型別[4]。也即excel isam查詢某列前幾行(預設情況下是8行),把佔多的型別作為其處理型別。例如如果數字佔多,那麼其它含有字母等文字的資料項就會置空;相反如果文字居多,純數字的資料項就會被置空。   現具體分析在第1節程式**extended properties項中的hdr和imex所代表的含義。hdr用來設定是否將excel表中第一行作為欄位名,「yes」代表是,「no」代表不是即也為資料內容;imex是用來告訴驅動程式使用excel檔案的模式,其值有0、1、2三種,分別代表匯出、匯入、混合模式。當我們設定imex=1時將強制混合資料轉換為文字,但僅僅這種設定並不可靠,imex=1只確保在某列前8行資料至少有乙個是文字項的時候才起作用,它只是把查詢前8行資料中資料型別佔優選擇的行為作了略微的改變。例如某列前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驅動的這種機制還是讓這列的資料變成空。      4 解決方法   從以上的分析中可以得知,當某列資料中含有混合型別時,在.net中使用microsoft.jet.oledb.4.0來讀取excel檔案造成資料丟失是不可避免的,要解決這個問題只能考慮採用其它資料讀取方法。   在.net中讀取excel檔案的另外一種方法是回到使用傳統com元件,這種方法在很多技術文章或**中都有涉及,本文不作贅述。需要指出的是,使用com元件來讀取excel檔案資料的效率較低,在作釋放的時候有可能碰到不可預知的錯誤,特別開發web應用的程式應該慎重使用。  

本文提出另外一種利用讀取csv純文字格式解決此問題的方法。   (1)在讀取excel的.xls型別的文字資料之前,先將其轉換為.csv格式,在excel中直接另存為這種格式就可以達到轉換的目的。csv檔案又稱為逗號分隔的檔案,是一種純文字檔案,它以「,」分隔資料列,本文表1的資料表用csv格式儲存後用純文字編輯器開啟的表現形式如表3所示。   表3 採用csv格式儲存的表1資料   需要指出的是,csv檔案也可以用ole db或odbc的方式讀取,但是如果採用這些方式讀取其資料又會回到丟失資料的老路上,isam機制同樣會發揮作用。   (2)採用普通的讀取文字檔案的方法開啟檔案,讀取第一行,用「,」作為分隔符獲得各欄位名,在datatable中建立對應的各欄位,欄位的型別可以統一建立成「string」。    本文原文

(3)逐行讀取資料行, 用「,」作為分隔符獲得某行各列的資料並填入datatable相應的字段中。   實現的簡化**如下:   string line;   string split = null;   datatable table=new datatable("auto");   datarow row=null;   streamreader sr=new streamreader("c:/auto.csv",system.text.encoding.default);   //建立與資料來源對應的資料列   line = sr.readline();   split=line.split(',');   foreach(string colname in split)   //將資料填入資料表   int j=0;   while((line=sr.readline())!=null)    table.rows.add(row);}    sr.close();   //顯示資料   datagrid1.datasource=table.defaultview;   datagrid1.databind();      5 結語   在應用程式的設計中,需要訪問excel資料的情況非常普遍,本文以在.net中對訪問含有混合型別資料的excel**擬採取的方法進行**。當然,如果不存在混合型別的資料使用microsoft.jet.oledb為較佳方案。對於不是使用.net開發的情況,本**的分析和所提供的方法亦可參考。   參考文獻:   [1]linuxmine.利用asp.net來訪問excel文件[eb/ol]. http://www.linuxmine.com/77726.html,2007-1-22.   [2]劉洪成.c#高階程式設計[m]. 北京:清華大學出版社,2003. 187-200.   [3]肖正巨集,曹元大,韓秋風.資料訪問技術——dao、ado、rdo的比較[j].電腦與資訊科技,2001,(1):31-32.   [4]pbr.excel使用dao openrecordset null作為返回值[eb/ol].http://support.microsoft.com/kb/194124,2004-6-24.   本文中所涉及到的圖表、註解、公式等內容請以pdf格式閱讀原文

Excel資料匯入至Dataset中

public static dataset exceltodataset string ppfilenameurl,string pptable microsoft.jet.oledb.4.0是microsoft jet引擎,這適用於2003版本,而在2007中,微軟對其旗下 access 與 ex...

Python讀入Excel資料存入MySQL

import xlrd import pymysql from datetime import datetime from xlrd import xldate as tuple 開啟資料所在的工作簿,以及選擇存有資料的工作表 book xlrd.open workbook 測試表.xls shee...

上傳Excel,並將Excel內容儲存到資料庫

前台頁面 text align right 序列號資訊 filesn runat server btnsn runat server text 上傳 onclick btnsn click 後台 新增引用 using system.io protected void btnsn click obje...