在应用程序的设计中,常常须要读取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),以此完全解决限制问题。若是该篇博文对你有帮助,但愿点个关注支持下。