C#彻底解决Oledb连接Excel数据类型不统一的问题

彻底解决Oledb连接Excel数据类型不统一的问题

在使用Microsoft.Jet.OLEDB.4.0连接Excel,进行读取数据,相对使用传统的COM来读取数据,效率是很高的。但相对传统COM操作Excel来说,及存在数据类型转换的问题。

因为使用OLEDB连接Excel读取数据时,需要确定数据的类型。默认情况使用连接字符串:

view source

print
?

1.
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + excelFile + ";Extended Properties=‘Excel 8.0;‘";

使用上面的连接字符串连接Excel时,可能会遇到数据类型不一致的问题。所谓数据类型不一致,是指同一列里面数据类型可能出现多种,如浮点数、字符串、日期等;当出现此类情况时,读取出来的数据就为空,甚至会报错,如“非法的日期格式”等异常。出现这种问题,我们大家都会想到把数据全部都按字符数据来读取,但是按什么数据类型来读取不是我们能控制的,是OLEDB控制的,至少暂时我还没有找到能控制输出数据类型的方法。因为我当初也尝试使用convert,cast函数对输出的列进行类型转换,但oledb连接Excel时,使用的SQL不支持这些函数。因此只能从其他角度来解决该问题。我也在网上搜索了很多解决方法,最全面的解决方法是:http://www.douban.com/note/18510346/。下面列出了网上出现解决该问题方法的比较:

解决方案 说明 缺点
COM 使用Excel COM接口访问Excel 非托管、不容易释放资源、效率低下
连接字符串添加IMEX=1 构造的连接字符串,如:

view source

print
?

1.
string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + excelFile + ";Extended Properties=‘Excel 8.0;HDR=YES;IMEX=1‘";

其中HDR表示是否将Sheet页的第一行作为字段名,“YES”代表是,“NO”代表不是,当为YES时,将把SHEET页的第一行作为字段名,数据从第二行开始,而如果是NO时,字段名就是要SHEET的列名,如A,B,C等,数据就从第一行开始取;IMEX是用来告诉驱动程序,使用Excel文件的模式,其值有0、1、2三种,分别代表导出、导入、混合模式。当我们设置IMEX=1时将强制混合数据转换为文本,但仅仅这种设置并不可靠,IMEX=1只确保在某列前8行数据至少有一个是文本项的时候才起作用,它只是把查找前8行数据中数据类型占优选择的行为作了略微的改变。例如某列前8行数据全为纯数字,那么它仍然以数字类型作为该列的数据类型,随后行里的含有文本的数据仍然变空。 (摘至:http://www.douban.com/note/18510346/)。

只根据前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驱动的这种机制还是让这列的数据变成空。 (摘至:http://www.douban.com/note/18510346/)。 修改注册表不方便,而且无法事先判读sheet有多少行,因此还是受行数限制。
将Excel先转换成csv纯文本格式

(1)在读取Excel的.xls类型的文本数据之前,先将其转换为.csv格式,在Excel中直接另存为这种格式就可以达到转换的目的。CSV文件又称为逗号分隔的文件,是一种纯文本文件,它以“,”分隔数据列。

需要指出的是,CSV文件也可以用Ole DB或ODBC的方式读取,但是如果采用这些方式读取其数据又会回到丢失数据的老路上,ISAM机制同样会发挥作用。

(2)采用普通的读取文本文件的方法打开文件,读取第一行,用“,”作为分隔符获得各字段名,在DataTable中创建对应的各字段,字段的类型可以统一创建成“String”。

(3)逐行读取数据行, 用“,”作为分隔符获得某行各列的数据并填入DataTable相应的字段中。

简要代码:

view source

print
?

01.
String line;

02.
String [] split = null;

03.
DataTable table=new DataTable("auto");

04.
DataRow row=null;

05.
StreamReader sr=newStreamReader("c:/auto.csv",System.Text.Encoding.Default);

06.
//创建与数据源对应的数据列

07.
line = sr.ReadLine();

08.
split=line.Split(‘,‘);

09.
foreach(String colname in split){

10.
  table.Columns.Add(colname,System.Type.GetType("System.String"));

11.
}

12.
//将数据填入数据表

13.
int j=0;

14.
while((line=sr.ReadLine())!=null){

15.
  j=0;

16.
  row = table.NewRow();

17.
  split=line.Split(‘,‘);

18.
  foreach(String colname in split){

19.
      row[j]=colname;

20.
      j++;

21.
   }

22.
  table.Rows.Add(row);

23.
}

24.
sr.Close();

25.
//显示数据

26.
dataGrid1.DataSource=table.DefaultView;

27.
dataGrid1.DataBind();

(摘至:http://www.douban.com/note/18510346/)。

需要事先将excel转换成csv文件

这里提供一个更加方便的办法,不过前提是第一行必须是作为字段名或者第一行的数据类型就为字符型。这样一说,大家就明白了。首先修改连接字符串为:

view source

print
?

1.
string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + excelFile + ";Extended Properties=‘Excel 8.0;HDR=NO;IMEX=1‘";

这里将HDR设为NO,因为我就是将第一行做为数据读取,而IMEX=1就表示根据前8行判断列的数据类型,如果有字符型数据,那么就强制混合数据转换为文本。这里就明白为什么要保证第一行为字符型的原因了。能将列的数据类型强制设为字符型,那么列中出现什么类型的数据都不怕了。需要做的工作就是,在获取完数据后,将字段名重新设置,并删除第一条记录即可。代码如下:

view source

print
?

01.
DataTable dt = new DataTable();

02.

03.
using(OleDbCommand cmd = new OleDbCommand()){

04.
    cmd.Connection = conn;

05.
    cmd.CommandType = CommandType.Text;

06.
    cmd.CommandTimeout = 6;

07.
    cmd.CommandText = string.Format("select * from [{0}$]", sheetName);

08.

09.
    OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);

10.
    adapter.Fill(dt);

11.
}

12.

13.
if (dt.Rows.Count > 0) {

14.
    DataRow dr = dt.Rows[0];

15.

16.
    for (int col = 0; col < dt.Columns.Count; col++) {

17.
        dt.Columns[col].ColumnName = dr[col].ToString();

18.
    }

19.

20.
    dt.Rows[0].Delete();

21.
    dt.AcceptChanges();

22.
}

时间: 2024-10-13 20:44:35

C#彻底解决Oledb连接Excel数据类型不统一的问题的相关文章

C#使用oledb连接excel执行Insert Into语句出现“操作必须使用一个可更新的查询”的解决办法

我发生错误时的环境:Windows 7,Framework 4.0,Microsoft Office 2007,VS2010,c# WinForm: 部分代码: string strConn = "Provider=Microsoft.Ace.OleDb.12.0;Persist Security Info=False;" + "data source=" + @excelPath + ";Extended Properties='Excel 12.0;

关于OleDB连接Excel的Extended Properties(扩展属性)HDR=YES; IMEX=2个人理解心得

最近在用C#写一个创建Excel并将数据导出到Excel的WinForm程序, 让我对OleDB连接Excel的Extended Properties(扩展属性)HDR=YES; IMEX=2有了深刻的认识! 参数HDR的值: HDR=Yes,这代表第一行是标题,不做为数据使用 ,如果用HDR=NO,则表示第一行不是标题,做为数据来使用.系统默认的是YES参数Excel 8.0 对于Excel 97以上到2003版本都用Excel 8.0,2007或2010的都用Extended Propert

使用oledb读写excel出现“操作必须使用一个可更新的查询”的解决办法

使用oledb读写excel出现"操作必须使用一个可更新的查询"的解决办法 转自:http://www.cnblogs.com/Richinger/archive/2008/09/28/1301170.html 前两天使用oledb连接excel的办法为单位某部门从一个excel的多个sheet中作连选抽出需要的数据,程序非常简单,结果很快就出来,原来手工需要很长时间才能选出的结果现在几乎一点击就有了结果.使用人员非常满意,由于是多人使用,开始只是将结果显示在一个页面上.后来他们要求将

一起学微软Power BI系列-使用技巧(2)连接Excel数据源错误解决方法

上一篇文章一起学微软Power BI系列-使用技巧(1)连接Oracle与Mysql数据库中,我们介绍了Power BI Desktop中连接Oracle和Mysql的方法,其实说到底还是驱动的问题,还有就是坑爹的驱动版本问题.换了新电脑,在导入模型时,居然碰到了Excel导入错误的情况.顺便记下来吧.其实还是驱动的问题. 1.连接Excel文件错误 新电脑连接Excel居然报错... 2.解决方法 详细的解决方法和说明可以参考PBD的中文文档:https://powerbi.microsoft

ADO.NET(OleDb)读取Excel表格时的一个BUG

如果我们有例如以下一个Excel表格: 如今要使用C#程序读取其内容: using System; using System.Data.OleDb; namespace Skyiv.Ben.Test {   sealed class ExcelTest   {     static void Main()     {       try       {         using (OleDbConnection conn = new OleDbConnection("Provider=Micr

关于oledb对Excel的读取(转)

这两天项目需求要检索excel的内容,于是就研究了一下,话不多说,我就直接贴代码1.首先是连接excel. public DataTable SearchSheetToDT(string strSearch, string sheetName) { //文件路径 string path = Server.MapPath("~/Content/custom/Excel1.xlsx"); //连接表字符串 string ExcelConnection = "Provider=Mi

Niagara解决设备连接应用的软件框架平台技术。

Niagara 是Tridium公司所研发的设计用于解决设备连接应用的软件框架平台技术. Niagara是一种应用框架,或者说是软件框架,特别设计用于应对智能设备所带来的各种挑战,包括设备连接到企业级的应用,支持互联网的产品和基于互联网自动化系统的开发. 应用框架是一个软件工程中的概念,不同于普通的软件,它是用于实现某应用领域通用完备功能的底层服务,使用这种框架的编程人员可以在一个通用功能已经实现的基础上开始具体的产品和系统开发.应用框架强调的是软件的设计重用性和系统的可扩展性,以缩短各种应用软

.NET中使用OleDb读取Excel

在.NET中可以用OleDb(Object linking and embeding DataBase)来访问Excel 1 using System; 2 using System.Data; 3 using System.Windows.Forms; 4 using System.Data.OleDb; 5 6 namespace ExcelDemo 7 { 8 public partial class Form1 : Form 9 { 10 public Form1() 11 { 12 I

oledb 操作 excel

oledb excel http://wenku.baidu.com/search?word=oledb%20excel&ie=utf-8&lm=0&od=0 [Asp.net]常见数据导入Excel,Excel数据导入数据库解决方案,总有一款适合你! http://www.cnblogs.com/wolf-sun/p/3589605.html asp.net操作Excel(向excel模板添加数据) http://www.cnblogs.com/Silverlight_Team/