• OLEDB 连接EXCEL的连接字符串IMEX的问题(Oledb)


    今天碰到一个问题需要想EXCEL表中写数据,折腾了好久才发现是IMEX惹得祸,所以记录下提醒自己,也希望大家不要出同样的错。

    碰到问题:使用语句 "insert into [Sheet1$] (大类) values ('test')" 无法插入 。

    原因:Provider=Microsoft.Jet.OLEDB.4.0;Data Source='2008-08.xls'; Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'

     解决方法: 去掉IMEX=1

    补充:

    向EXCEL插入数据时 数据类型是由前8行数据中数据类型占优选择  

    例如:分数一列前前8行为空值 插入5为字符串格式,如果前8行为数字格式 插入5为数字格式关于IMEX的资料:

    IMEX是用来告诉驱动程序使用Excel文件的模式,其值有0、1、2三种,分别代表导出、导入、混合模式。当我们设置IMEX=1时将强制混合数据转换为文本,但仅仅这种设置并不可靠,IMEX=1只确保在某列前8行数据至少有一个是文本项的时候才起作用,它只是把查找前8行数据中数据类型占优选择的行为作了略微的改变。例如某列前8行数据全为纯数字,那么它仍然以数字类型作为该列的数据类型,随后行里的含有文本的数据仍然变空。 


      另一个改进的措施是IMEX=1与注册表值TypeGuessRows配合使用,TypeGuessRows 值决定了ISAM 驱动程序从前几条数据采样确定数据类型,默认为“8”。可以通过修改“HKEY_LOCAL_MACHINESOFTWAREMicrosoftJet4.0EnginesExcel”下的该注册表值来更改采样行数。但是这种改进还是没有根本上解决问题,即使我们把IMEX设为“1”, TypeGuessRows设得再大,例如1000,假设数据表有1001行,某列前1000行全为纯数字,该列的第1001行又是一个文本,ISAM驱动的这种机制还是让这列的数据变成空。

    解决办法:

    使用OLEDB可以对excel文件进行读取,我们只要把该excel文件作为数据源即可。

    一 在D盘创建excel文件test.xls:

      

    二 将工作表Sheet1的内容读取到DataSet
      string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:/test.xls;"+
          "Extended Properties='Excel 8.0'";
      DataSet ds = new DataSet();
      OleDbDataAdapter oada = new OleDbDataAdapter("select * from [Sheet1$]", strConn);
      oada.Fill(ds);

    读取的DataSet为:

      

    从图中可以看出excel文件中的第一行变成了DataSet中的列名,这正是系统的默认设置。

    三 如果想把第一行也作为数据行,那我们可以给连接字符串添加一个HDR=No属性如:
      string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:/test.xls;"+
          "Extended Properties='Excel 8.0;HDR=No'";
      DataSet ds = new DataSet();
      OleDbDataAdapter oada = new OleDbDataAdapter("select * from [Sheet1$]", strConn);
      oada.Fill(ds);
      结果也许会让你有点想不到:

      

    第一行的第一列和第三列都变成空的了,这是因为系统把第一列识别成了数字,把第三列识别成了日期,

    而第一行的数据不符合格式的要求,所以就变成空的了。

    四 我们还可以把所有列都做为字符串来读取,只要添加属性IMEX=1即可

      string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:/test.xls;"+
          "Extended Properties='Excel 8.0;HDR=No;IMEX=1'";
      DataSet ds = new DataSet();
      OleDbDataAdapter oada = new OleDbDataAdapter("select * from [Sheet1$]", strConn);
      oada.Fill(ds);
      结果又会如何呢?

      

    是不是再次出乎你的意料,第三行的日期怎么变成数字了,其实excel在转换格式的时候就自动把日期变成数字了,

    那这个数字是怎么来的呢 ? 如果你把日期改成1900年1月1日,那么你可以看到他的转换结果是1,以此类推,39902是哪一天就明白了吧。

    这里解决办法:

    方法一:
      public static string getDateStr(string strValue)
          {
              int i = Convert.ToInt32(strValue);
              DateTime d1 = Convert.ToDateTime("1900-1-1");
              DateTime d2 = d1.AddDays(i - 2);
              string strTemp = d2.ToString("d");

              return strTemp;
          }
      方法二:
      DateTime.FromOADate(Convert.ToInt32(strValue)).ToString("d");

    五 也许你并不想读取整个excel的内容

    如果只想读取前两列可以用:select * from [Sheet1$A:B]

    如果只想读取A1到B2的内容,就用:select * from [Sheet1$A1:B2]

    六 如果不知道工作表的名字或名字被人为修改了该怎么办呢?

    我们可以通过索引来获取指定工作表的名字,以下方法可以用来获取工作表名称的数组:


      ArrayList al = new ArrayList();
      string strConn;
      strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:/test.xls;"+
          "Extended Properties=Excel 8.0;";
      OleDbConnection conn = new OleDbConnection(strConn);
      conn.Open();
      DataTable sheetNames = conn.GetOleDbSchemaTable
          (OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
      conn.Close();
      foreach (DataRow dr in sheetNames.Rows)
      {
          al.Add(dr[2]);
      }
      return al;

    IMEX=1的时候并不是全都会作为字符串来处理,根据系统的默认设置,通常如果前8行有字符串,则该列会作为字符串来处理,如果全都为数字,则该列为数字列,日期也是一样。

    如果你觉得8行不够或者太多了,则只能修改注册表HKEY_LOCAL_MACHINE/Software/Microsoft/Jet/4.0/Engines/Excel/TypeGuessRows,如果此值为0,则会根据所有行来判断使用什么类型,通常不建议这麽做,除非你的数据量确实比较少。 

    无法读取EXCEL中的数据单元格。有数据,但是读出来全是空值。

    解决方法:

    1.在导入数据连接字符串中,将IMEX=1加入,“Provider=Microsoft.Jet.OLEDB.4.0;Data Source="C:Data.xls";Extended Properties="Excel 8.0;HDR=Yes;IMEX=1; ”,这样就可以。

    注:

    “HDR=Yes;”指示第一行中包含列名,而不是数据;

    “IMEX=1;”通知驱动程序始终将“互混”数据列作为文本读取。

    两者必须一起使用。

    本以为这样就OK了。但在实际使用过程中,这样设置还是不行,查阅了不少资料才发现,原来还有一个注册表里的信息需要修改,这样带能让excel不再使用前8行的内容来确定该列的类型。

    注册表修改内容如下:

    在HKEY_LOCAL_MACHINESoftwareMicrosoftJet4.0EnginesExcel有一个TypeGuessRows值,预设是8,表示会先读取前8列来决定每一个栏位的型态,所以如果前8列的资料都是数字,到了第9列以后出现的文字资料都会变成null,所以如果要解决这个问题,只要把TypeGuessRows机码值改成0,就可以解这个问题了。

  • 相关阅读:
    javascript性能
    图片及js的预加载
    url参数解析
    javascript预编译
    13、MVC 设计思想
    12、JDBC 流程
    线程-2、sleep() 、join()、yield()有什么区别
    线程-1、创建线程的方式及实现
    集合-7、HashMap实现原理及源码分析
    集合-6、HashSet 和 HashMap 区别
  • 原文地址:https://www.cnblogs.com/tianma3798/p/3597766.html
Copyright © 2020-2023  润新知