C#读取Excel数据丢失问题的解决方法
最近发现在Excel数据中的某一列存在日期和字母混合类型的数据时,C#读取到的Excel的数据将非日期类型的数据丢失了,读到的全部为“null”值,这个问题纠结了半天,在网上找到了解决方法。
方法一:
更新Excel的连接字符串:
之前的:{0}和{1}占位符分别为:Excel文件的路径和版本信息。
private const string ConnectionStringTemplate = "Provider = Microsoft.ACE.OLEDB.12.0; Data Source ={0};Extended Properties=Excel {1}; ";
应该更新为:
private const string ConnectionStringTemplate = "Provider = Microsoft.ACE.OLEDB.12.0; Data Source ={0};Extended Properties='Excel {1};IMEX=1' ";
这里大家请注意,之前在网上看到很多的也是这种解决方法,可是连接字符串的此部分:
Extended Properties='Excel {1};IMEX=1'
少了单引号,导致程序一直会出现“未找到可安装的ISAM”的异常,后来加上就解决了空值的问题了。不过这种方法,默认对于该列的前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驱动的这种机制还是让这列的数据变成空。
所以此方法适合确定多少行肯定为混合型的数据的Excel文件。
方法二:
在之前一直不知方法一问题出在哪的时候,尝试其它的解决方法,想到是否可以直接打开excel文件,逐行读取Excel数据的方法,很庆幸这个也可以达到期望的效果。不过,有个缺点就是,此方法执行需要花费较多的时间。具体方法如下,仅供参考:
/// <summary> /// 直接打开Excel,逐行读取数据 /// </summary> /// <param name="strPath">Excel文件路径</param> /// <param name="strName">读取的表名</param> /// <param name="lable">label进度</param> /// <returns>Excel数据存入的DataTable</returns> public static DataTable Excel2DataTableDirect(string strPath, string strName, Label lable) { Excel.Application excel = null; Excel.Workbooks wbs = null; Excel.Workbook wb = null; Excel.Worksheet ws = null; Excel.Range range1 = null; object Nothing = System.Reflection.Missing.Value; DataTable dt = new DataTable(); excel = new Excel.Application(); excel.UserControl = true; excel.DisplayAlerts = false; excel.Application.Workbooks.Open(strPath, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing); wbs = excel.Workbooks; wb = wbs[1]; ws = (Excel.Worksheet)wb.Worksheets[strName]; //获取行数 int rowCount = ws.UsedRange.Rows.Count; //获取列数 int colCount = ws.UsedRange.Columns.Count; if (rowCount <= 0) MessageBox.Show("此Excel为空!"); if (colCount < 33) MessageBox.Show("此Excel列数不对!"); //循环给DataTable数据赋值 for (int i = 1; i <= rowCount; i++) { DataRow dr = dt.NewRow(); for (int j = 1; j < 33; j++) { range1 = ws.Range[ws.Cells[i, j], ws.Cells[i, j]]; //range1 = ws.get_Range(ws.Cells[i, j], ws.Cells[i, j]); if (i == 1) dt.Columns.Add((string)range1.Value); dr[j - 1] = range1.Value; } lable.Text = "Importing lines:" + i + "/" + rowCount; dt.Rows.Add(dr); } //释放Excel if (excel != null) { if (wbs != null) { if (wb != null) { if (ws != null) { if (range1 != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(range1); range1 = null; } System.Runtime.InteropServices.Marshal.ReleaseComObject(ws); ws = null; } wb.Close(false, Nothing, Nothing); System.Runtime.InteropServices.Marshal.ReleaseComObject(wb); wb = null; } wbs.Close(); System.Runtime.InteropServices.Marshal.ReleaseComObject(wbs); wbs = null; } excel.Application.Workbooks.Close(); excel.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(excel); excel = null; GC.Collect(); } return dt; }