最近由于工作上用到了读取Excel操作,完成过程中遇到了各种各样的问题,最后为了以后读取Excel时不再如此的麻烦,特意做成了一个小组件,方便日后使用。现在总结一下过程中遇到的问题及相应的解决办法。

一、Excel读取方式及问题

第一种方式:通过OleDb连接,把excel文件作为数据源来读取

优点:读取的效率很快。

缺点:1、读取过程中需要依赖于计算机安装的office版本,不同的版本读取过程中用到的代码会有所不同,这就需要在实现的过程中必须判断客户端机器安装的office版本(如果客户端未装任何版本的office软件,则程序将会报错);

2、读取Excel得到的工作表名称即Sheet名称会和Excel表格中实际的Sheet名称有所不一致 ,不过这并不妨碍程序的运行;

3、如果Excel表格中存在这样的列:列中的数据类型不一致,比如说列中一些行为数字,一些行为字符串,那么将有一种类型的数据部分解析不出来,显示为空,产生这种问题的根源与Excel ISAM[3](Indexed Sequential Access Method,即索引顺序存取方法)驱动程序的限制有关,Excel ISAM 驱动程序通过检查前几行中实际值确定一个 Excel 列的类型,然后选择能够代表其样本中大部分值的数据类型[4]。也即Excel ISAM查找某列前几行(默认情况下是8行),把占多的类型作为其处理类型。例如如果数字占多,那么其它含有字母等文本的数据项就会置空;相反如果文本居多,纯数字的数据项就会被置空。 若要修改默认情况下的8行,需要修改注册表值TypeGuessRows,TypeGuessRows 值决定了ISAM 驱动程序从前几条数据采样确定数据类型,默认为“8”。可以通过修改“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel”下的该注册表值来更改采样行数。但是这种改进还是没有根本上解决问题。遇到这种情况时应当考虑不再使用这种读取Excel表格的方式。

第二种方式:引用Com组件读取Excel文件。

        优点:无需考虑客户端机器安装的Office版本,读取的Sheet名称和Excel表格中完全一致,也不需要考虑Excel表格中列中的数据类型是否不一致,读取的数据十分准确。

缺点:1、效率比较低,读取的过程耗时严重;

              2、需要做好内存的释放、Excel进程的关闭工作。

二、读取方式详解及问题解决办法总结

第一种方式:通过OleDb连接,把excel文件作为数据源来读取

1、方式详解:该方式主要的部分为两步:第一步,需要解析Excel表中的所有Sheet名称,如下面的代码,我将得到的所有Sheet名称放到了一个Lsit<string>集合集合中(_workSheets),并在代码段将该集合绑定到了下拉框cmbxWorkSheets;

string conn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + SourceExcelFile + ";Extended Properties=\"Excel 8.0;HDR=YES;IMEX=1;\"" ;OleDbConnection conn = new OleDbConnection(connString);
conn.Open();
DataTable dt = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
conn.Close();foreach (DataRow row in dt.Rows){string name = row["TABLE_NAME"].ToString();if (!name.Contains("$"))continue;_workSheets.Add(name);}

第二步,根据选择的Sheet,读取excel表格中相应sheet名称的数据

string conn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + SourceExcelFile + ";Extended Properties=\"Excel 8.0;HDR=YES;IMEX=1;\"" ;string sql = string.Format("select * from [{0}]", cmbxWorkSheets.Text);
OleDbDataAdapter da = new OleDbDataAdapter(sql, conn);
DataSet ds = new DataSet();da.Fill(ds);
if (ds != null && ds.Tables.Count > 0)dt = ds.Tables[0];

这样,读取过程基本完成。
      2、方式问题及解决:

问题1:在上面用到的连接字符串 string conn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + SourceExcelFile + ";Extended Properties=\"Excel 8.0;HDR=YES;IMEX=1;\"" ,其中Provider=Microsoft.ACE.OLEDB.12.0,对于不同的offcie版本,Provider对应的值会有所不同,07及以上版本为Microsoft.ACE.OLEDB.12.0,而03版本的office却为Microsoft.Jet.OLEDB.4.0,因此需要判断客户端安装的office版本以确定Provider的值,而不能像上面那样直接写死。

  /// <summary>/// 判断Excel的版本号。/// </summary>/// <returns></returns>private static double CheckExcelVer(){Type objExcelType = Type.GetTypeFromProgID("Excel.Application");if (objExcelType == null){return 0;}object objApp = Activator.CreateInstance(objExcelType);if (objApp == null){return 0;}object objVer = objApp.GetType().InvokeMember("Version", BindingFlags.GetProperty, null, objApp, null);double iVer = Convert.ToDouble(objVer.ToString());objVer = null;objApp = null;objExcelType = null;GC.Collect();return iVer;}/// <summary>/// 根据Excel版本号获得Excel的版本名称。/// </summary>/// <returns></returns>public static String GetExcelVerStr(){String version;double excelver;excelver = CheckExcelVer();// ExistsExcelRegedit();version = "Office ";if (excelver == 0){MessageBox.Show("无法识别Excel的版本", "错误", MessageBoxButtons.OK, MessageBoxIcon.Information);version = "无法识别 office 版本";}else if (excelver >= 14) version += "2010或以上";else if (excelver >= 12) version += "2007";else if (excelver >= 11) version += "2003";else if (excelver >= 10) version += "XP";else if (excelver >= 9) version += "2000";else if (excelver >= 8) version += "97";else if (excelver >= 7) version += "95";return version;}/// <summary>/// 根据Excel的版本名称获得Provider。/// </summary>/// <returns></returns>public static string GetExcelProvider(){string provider = string.Empty;string version = GetExcelVerStr();switch (version){case "Office 2010或以上":case "Office 2007":provider = "Microsoft.ACE.OLEDB.12.0";break;case "Office 2003":case "Office 2000":case "Office XP":case "Office 97":case "Office 95":provider = "Microsoft.Jet.OLEDB.4.0";break;}return provider;}

这样就可以根据用户客户端安装的office版本来读取Excel,只要客户端安装了office解析Excel时便不会出错。

问题二:Excel表格中某些列中数据类型不一致,导致列中后面的数据读取不出来。这种方式在读取Excel表的时候,无法定义和修改读取列的数据类型,string conn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + SourceExcelFile + ";Extended Properties=\"Excel 8.0;HDR=YES;IMEX=1;\"" ,虽然“IMEX = 1”被认为是用来解决数字与字符混合时,识别不正常的情况,但其实它并未真正解决问题,表现为如果某字段前8条记录中全部为纯数字的话,那么在该字段随后的记录中含有字母或汉字的项将仍然变为空,但是如果该字段前8条记录中有一条不为纯数字,将能得到预期想要的结果,也就是说它其实只对前8行中不一致的数据类型起作用,8行之后的数据若出现数据不一致,便会出现为空的情况。此时,若要更好的解决问题,需要用第二种方式来读取Excel表。

第二种方式:引用Com组件读取Excel文件。

1、方式详解

这种方式需要添加COM中的程序集Microsoft Excel 11.0 Object Library.dll,修改程序集中的属性“嵌入互操作类型”为False,不然会提示错误: 无法嵌入互操作类型“Microsoft.Office.Interop.Excel.ApplicationClass”。读取Excel的代码:

        private Microsoft.Office.Interop.Excel.ApplicationClass _excelApp;private Microsoft.Office.Interop.Excel._Workbook _workbook;private Microsoft.Office.Interop.Excel.Sheets _workSheets;_excelApp = new Microsoft.Office.Interop.Excel.ApplicationClass();_excelApp.Visible = true;_workbook = _excelApp.Workbooks.Open(fileName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value) as Microsoft.Office.Interop.Excel.WorkbookClass;_workSheets = _workbook.Sheets;private void ReadExcel(){Excel.Range selectedRange = _excelApp.Selection as Excel.Range;try{if (ResultTable != null){ResultTable.Clear();ResultTable.Dispose();}ResultTable = new DataTable();string colName = string.Empty;if (IncludeHeader){for (int i = 1; i <= selectedRange.Columns.Count; i++){Excel.Range cell = selectedRange[1, i] as Excel.Range;if (cell != null && cell.Value != null)colName = cell.Value.ToString().Trim();elsecolName = string.Empty;if (string.IsNullOrEmpty(colName))colName = "列 " + i.ToString();if (ResultTable.Columns.Contains(colName))throw new Exception(string.Format("导入数据存在重复的列:{0}。", colName));ResultTable.Columns.Add(new DataColumn(colName));}}else // 若不含标题行,则列名自动命名为“列 1”、“列 2”等。for (int i = 1; i <= selectedRange.Columns.Count; i++)ResultTable.Columns.Add(new DataColumn("列 " + i.ToString()));int firstDataLineNo = IncludeHeader ? 2 : 1;    // 若不含标题行,数据从第一行开始。int count = selectedRange.Rows.Count;for (int i = firstDataLineNo; i <= count; i++){//if (((Excel.Range)selectedRange[i, 1]).Value == null)//    continue;
DataRow dr = ResultTable.NewRow();for (int j = 0; j < selectedRange.Columns.Count; j++)dr[j] = ((Excel.Range)selectedRange[i, j + 1]).Value;ResultTable.Rows.Add(dr);SetProgressValue(count - firstDataLineNo, i - firstDataLineNo);}}catch (Exception exp){MessageBox.Show(this, string.Format("读Excel错误:{0}", exp.Message), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);_excelApp.Visible = true;}}

方式问题及解决:

这种方式效率很慢,而且需要做好善后工作。释放内存:

        private void DisposeExcelResource(){try{if (_workbook != null)_workbook.Close(false, Missing.Value, false);if (_excelApp != null)_excelApp.Quit();System.Runtime.InteropServices.Marshal.ReleaseComObject(_excelApp);System.Runtime.InteropServices.Marshal.ReleaseComObject(_workbook);//System.Runtime.InteropServices.Marshal.ReleaseComObject( _selectedRange );
GC.Collect();}catch{}}

但上面这些做不到关闭打开的Excel文件,若需要做到关闭Excel文件:

        [DllImport("User32.dll", CharSet = CharSet.Auto)]public static extern int GetWindowThreadProcessId(IntPtr hwnd, out   int ID);public void BeforeClosing(){if (_excelApp != null){IntPtr t = new IntPtr(_excelApp.Hwnd);int k = 0;GetWindowThreadProcessId(t, out k);System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k);p.Kill();}}

三、总结
        花了一定的时间,工作上想实现的实现了,同时也将问题的解决总结了下来。这个过程自己有很大的收获,以后遇到问题时也一定要像现在这样将问题深入全面的了解并解决,多解决问题,多总结解决问题的过程,这样才能让自己寒酸的技术和表达能力一点一点的得到提高。

       

转载于:https://www.cnblogs.com/huachen/p/3382363.html

C#Excel文件读取问题及解决办法相关推荐

  1. vue使用XSLX,用CDN引入后下载的excel文件无法打开的解决办法

    目的:优化首屏加载速度 使用npm打包的体积: 引用cdn打包后的体积: 使用npm安装在项目里的xlsx插件,下载的文件是没问题的,但发现了引入CDN后下载的文件无法打开: 解决办法:查看node_ ...

  2. ArcGIS操作Excel文件没有注册类解决办法

    在ArcGIS Desktop中进行表连接时选择了一张excel表,但添加该表时报错: 原因是机器上缺少Office的数据驱动. ArcGIS 支持 : Excel 2003 以及更早版本的 .xls ...

  3. Excel打开csv文件出现乱码的解决办法

    excel打开是乱码怎么办?该如何解决呢?打开excel遇到乱码也是很常见的现象. excel打开是乱码的解决办法: 1.Excel打开一个csv格式的文档,出现乱码; 2.有乱码的 CSV 档透过记 ...

  4. PyQt5随笔:PyQt5 程序在开机自启动时读取文件出错导致崩溃解决办法

    PyQt5随笔:PyQt5 程序在开机自启动时读取文件出错导致崩溃解决办法 1.前言 最近在写一个 Python+pyqt5 小项目,在改善过程中想添加一个日志记录,我是打算用txt 文件记录就好,操 ...

  5. Excel 2013 打开文件为灰色,解决办法

    双击打开桌面test.xlsx文件,结果出现空白. 在文件->打开->test.xlsx可以打开文件,但是每次都这样打开文件比较麻烦. 解决办法: 文件->选项->高级 再次打 ...

  6. Python 办公效率化学习(自学)三.Excel文件读取

    目录 Excel文件读取 Day1 一.步骤解析(以统计火龙果可乐为例) 二.具体操作 1.读取单个月份Excel表格数据 (1)首先学习Excel基本结构: (2)分析得出需要的步骤 : (3)前提 ...

  7. oracle 表空间文件达到32G后解决办法

    数据库报错:"ORA-01654: 索引...无法通过8192(在表空间...中)扩展".或者:ora-01652无法通过128(在表空间temp中)扩展temp段,这种错误信息时 ...

  8. excel文件变成乱码如何解决?

    打开excel时有可能会出现乱码的情况,这个问题并不少见,下面小编就给大家介绍一下excel文件变成乱码的解决方法. 第一,CSV文件用excel打开是乱码 从网页导出的CSV文件, 用Excel打开 ...

  9. python实现Excel文件读取的程序(附源代码)

    python实现Excel文件读取的程序   前一段时间帮一个朋友用python写了一个读Excel程序操作的程序,具体要求为:读取两个Excel文件,根据其中某个特征的特征值对这两个文件进行取交集操 ...

最新文章

  1. python CST中国标准时间格式转换
  2. 【计算机网络】网络层 : DHCP 协议 ( DHCP 协议概念 | DHCP 协议特点 | DHCP 协议流程 )
  3. Mysql清空表(truncate)与删除表中数据(delete)的区别
  4. mysql 重装,Windows系统中完全卸载MySQL数据库实现重装mysql
  5. java常用的日期类介绍
  6. PTAM特征点法跟踪和建图 SLAM FAST Patch
  7. 怎么彻底粉碎文件夹?文件还能恢复吗?操作过程在这里
  8. Windows Server2012 服务器修改密码过期时间
  9. office972003_为什么我有Microsoft Office Excel 2003打不开Microsoft Office Excel 97-2003格式?...
  10. 打车日记 - 墨菲定律1609
  11. 教师资格综合素质知识要点记录
  12. Flutter启动流程(Isolate机制+创建流程+线程练习)
  13. 问题—抱怨?人品差?别搞笑了!
  14. 安卓逆向工程--针对授权key方式的破解
  15. echarts地图设置legend_echarts中关于自定义legend图例文字
  16. Tabby使用之:中文乱码问题
  17. 九天揽月带你玩转Ardupilot 的EKF2纸老虎
  18. Why Does Everyone Else Appear to Be Succeeding?
  19. 无人机算什么?波士顿动力的“ 机器狗 ” 也要开始送快递了
  20. IDEA Git操作(三)使用 cherry-pick、交互式 rebase 自由修改提交树

热门文章

  1. 【297天】我爱刷题系列056(2017.11.29)
  2. 使用Spring整合Quartz轻松完成定时任务
  3. 各种SQL在Pig中实现
  4. nagios中自己写的监控mysql主从复制的插件
  5. 轻松学习Linux之自动执行任务
  6. Oracle 学习笔记:Backup Recovery 常用命令
  7. 微信小程序 wx.request异步网络请求
  8. Pycharm 在Ubuntu图形界面中创建桌面图标
  9. OpenCV 对一张图片进行缩放
  10. CorelCAD 2020中文版