`
fordream
  • 浏览: 63569 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

OLEDB方式读取Excel丢失数据、字符串截断的原因和解决方法

阅读更多

1 引言
  在应用程序的设计中,经常需要读取Excel数据或将Excel数据导入转换到其他数据载体中,例如将Excel数据通过应用程序导入SQL Sever等数据库中以备使用。笔者在开发“汽车产业链ASP协同商务平台”中遇到了类似需求。某汽车整车生产企业需要将其车辆发车信息发布到汽车产业链平台上去,其数据为内部ERP系统生成的Excel数据表,用户首先将该数据表上传至汽车产业链平台,平台将此Excel数据读取导入到平台内部的SQL Sever数据库中,以供其它应用使用。汽车产业链平台的开发使用的开发工具为VS.NET,使用的语言是C#,在开发的过程中发现使用Microsoft.Jet.OLEDB.4.0读取数据会出现当某一字段内分别含有文本和数字的混合数据时,某一类型的数据会产生丢失。本文就对此问题产生的根源进行了分析并给出了相应的解决方法。


2 问题描述
  Excel是Microsoft公司的电子表格处理软件,在现代办公及企业信息化的应用中使用非常广泛,正因如此,在程序设计中我们经常要通过访问Excel文件来获得数据,但Excel文件不是标准数据库[1]。
  ASP.NET也是Microsoft公司的产品,作为.NET FrameWork框架中的一个重要组成部分,其主要用于Web设计。我们在.NET中访问读取Excel数据时一般采用Microsoft.Jet.OLEDB.4.0[2]。现以读取一个Excel文件auto.xls中sheet1工作表为例,工作表的内容如表1所示。
  表1 sheet1表的数据内容
  现将该表的数据内容读取并显示到到DataGrid中,简化的代码如下:
  

String ConnStr = " Provider = Microsoft.Jet.OLEDB.4.0; DataSource=f:/test.xls;Extended Properties='Excel 8.0;HDR=YES';"; 
  OleDbConnection Conn=new OleDbConnection(ConnStr); 
  Conn.Open(); 
  string SQL="select * from [sheet1$]"; 
  OleDbDataAdapter da=new OleDbDataAdapter(SQL,ConnStr); 
  DataSet ds=new DataSet(); 
  da.Fill(ds); 
  DataGrid1.DataSource=ds; 
  DataGrid1.DataBind(); 
  Conn.Close(); 

   但是运行以上代码的结果并不是期望的,它将显示为表2所示的内容。可以发现第一个字段中为“1042”的两个数据项变为空。
  表2 DataGrid1所显示的数据内容
  有程序设计人员将以上代码OleDbConnection连接字符串中的Extended Properties一项作了如下改动,Extended Properties='Excel 8.0;HDR=NO;IMEX=1’,认为可以解决此问题。由于在开发“汽车产业链协同商务平台”中碰到过类似问题,作了大量的测试后发现,添加IMEX=1后并未实质上解决此问题。表现为:如果某字段前8条记录中全部为纯数字的话,那么在该字段随后的记录中含有字母或汉字的项将仍然变为空,但是如果该字段前8条记录中有一条不为纯数字,将能得到预期想要的结果。

 

3 问题分析
  产生这种问题的根源与Excel ISAM[3](Indexed Sequential Access Method,即索引顺序存取方法)驱动程序的限制有关,Excel ISAM 驱动程序通过检查前几行中实际值确定一个 Excel 列的类型,然后选择能够代表其样本中大部分值的数据类型[4]。也即Excel ISAM查找某列前几行(默认情况下是8行),把占多的类型作为其处理类型。例如如果数字占多,那么其它含有字母等文本的数据项就会置空;相反如果文本居多,纯数字的数据项就会被置空。
  现具体分析在第1节程序代码Extended Properties项中的HDR和IMEX所代表的含义。HDR用来设置是否将Excel表中第一行作为字段名,“YES”代表是,“NO”代表不是即也为数据内容;IMEX是用来告诉驱动程序使用Excel文件的模式,其值有0、1、2三种,分别代表导出、导入、混合模式。当我们设置IMEX=1时将强制混合数据转换为文本,但仅仅这种设置并不可靠,IMEX=1只确保在某列前8行数据至少有一个是文本项的时候才起作用,它只是把查找前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驱动的这种机制还是让这列的数据变成空。


4 解决方法

  从以上的分析中可以得知,当某列数据中含有混合类型时,在.NET中使用Microsoft.Jet.OLEDB.4.0来读取Excel文件造成数据丢失是不可避免的,要解决这个问题只能考虑采用其它数据读取方法。
  在.NET中读取Excel文件的另外一种方法是回到使用传统COM组件,这种方法在很多技术文章或论文中都有涉及,本文不作赘述。需要指出的是,使用COM组件来读取Excel文件数据的效率较低,在作释放的时候有可能碰到不可预知的错误,特别开发Web应用的程序应该慎重使用。 

本文提出另外一种利用读取CSV纯文本格式解决此问题的方法。
  (1)在读取Excel的.xls类型的文本数据之前,先将其转换为.csv格式,在Excel中直接另存为这种格式就可以达到转换的目的。CSV文件又称为逗号分隔的文件,是一种纯文本文件,它以“,”分隔数据列,本文表1的数据表用CSV格式存储后用纯文本编辑器打开的表现形式如表3所示。
  表3 采用CSV格式保存的表1数据
  需要指出的是,CSV文件也可以用Ole DB或ODBC的方式读取,但是如果采用这些方式读取其数据又会回到丢失数据的老路上,ISAM机制同样会发挥作用。
  (2)采用普通的读取文本文件的方法打开文件,读取第一行,用“,”作为分隔符获得各字段名,在DataTable中创建对应的各字段,字段的类型可以统一创建成“String”。
  
本文原文
  (3)逐行读取数据行, 用“,”作为分隔符获得某行各列的数据并填入DataTable相应的字段中。
  实现的简化代码如下:
  

String line; 
  String [] split = null; 
  DataTable table=new DataTable("auto"); 
  DataRow row=null; 
  StreamReader sr=new StreamReader("c:/auto.csv",System.Text.Encoding.Default); 
  //创建与数据源对应的数据列 
  line = sr.ReadLine(); 
  split=line.Split(','); 
  foreach(String colname in split){ 
  table.Columns.Add(colname,System.Type.GetType("System.String")); } 
  //将数据填入数据表 
  int j=0; 
  while((line=sr.ReadLine())!=null){ 
   j=0; 
   row = table.NewRow(); 
   split=line.Split(','); 
   foreach(String colname in split){ 
   row[j]=colname; 
   j++;} 
   table.Rows.Add(row);} 
   sr.Close(); 
  //显示数据 
  dataGrid1.DataSource=table.DefaultView; 
  dataGrid1.DataBind(); 

 

 

说明:按照上面这篇文章分析当某列数据中含有混合类型时,在.NET中使用Microsoft.Jet.OLEDB.4.0来读取Excel文件造成数据丢失是不可避免的

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

 

经过测试原文的对这个解决方法的分析有误。

当修改TypeGuessRows 值为0时可以彻底解决这个问题

估计TypeGuessRows =0,程序就会默认行数为最大

分享到:
评论

相关推荐

    OLEDB读取Excel、csv出现字符串截断、丢失原因及其解决方案

    汽车产业链平台的开发使用的开发工具为VS.NET,使用的语言是C#,在开发的过程中发现使用Microsoft.Jet.OLEDB.4.0读取数据会出现当某一字段内分别含有文本和数字的混合数据时,某一类型的数据会产生丢失。本文就对此...

    C# WinFORM 窗体小程序 oledb技术读取EXCEL表格并展示

    这个项目就是一个典型的示例,它演示了如何使用OleDb技术来读取Excel表格的数据,并在窗体上通过DataGridView控件进行展示。下面将详细讲解这个过程涉及的知识点。 首先,`OleDb`(OLE DB)是微软提供的一种数据...

    C#以OleDb方式访问Excel2007所需文件的安装程序

    总结来说,"C#以OleDb方式访问Excel2007所需文件的安装程序"主要涉及的技术点包括C#编程、OleDb连接、AccessDatabaseEngine.exe组件、连接字符串构造以及数据的读写操作。理解并掌握这些知识点,可以帮助开发者有效...

    使用oledb读写excel出

    在进行数据处理与分析时,Excel 是一种非常常见的工具,而使用OLE DB (Object Linking and Embedding, Database)来读取或写入Excel文件则是一种高效且灵活的方式。本文将详细介绍如何使用OLE DB进行Excel文件的数据...

    C#操作Excel(OLEDB)

    OLEDB是微软提供的一种数据访问技术,允许程序与各种类型的数据源进行交互,包括Excel工作簿。 首先,我们要了解如何在C#中引入对Excel OLEDB的支持。这通常需要添加对"System.Data.OleDb"命名空间的引用。在Visual...

    Microsoft.ACE.OLEDB.12.0-提供程序

    【Microsoft.ACE.OLEDB.12.0-提供程序】本资源是C#程序使用OleDb读取Excel时必备的驱动程序——Microsoft.ACE.OLEDB.12.0的提供程序。OleDb是一个数据库驱动接口,能够通过标准的 SQL 语句访问多种数据库,包括 ...

    oledb连接字符串生成器(常用源代码)

    **OleDb连接字符串生成器**是开发者在使用OLE DB技术进行数据访问时,用来便捷创建有效连接数据库的重要工具。在Web开发中,特别是在ASP.NET环境中,配置正确的连接字符串是连接数据库的关键步骤。本文将深入探讨OLE...

    以ole方式读取excel文件

    在IT领域,以OLE(Object Linking and Embedding)方式读取Excel文件是一种常见的方法,尤其在编程中处理数据时非常实用。OLE是Microsoft开发的一种技术,它允许不同应用程序之间共享和嵌入对象。以下是对这个主题的...

    三种ASP.NET读取Excel文件的方法浅析(含完整代码)

    本文档介绍了一种通过OleDB访问Excel文件的方式,将其作为数据源来读取其中的数据。这种方法适用于Excel文件版本为97至2003之间的格式(.xls)。使用此方法时,需要确保目标计算机上已经安装了相应的Office组件或Jet...

    快速读取Excel C# 示例源码 OLEDB方式读取

    C# 示例源码 快速读取Excel,把Excel当成数据来源(Microsoft.Jet.OLEDB.4.0),可读取多张表,

    C#中读取Excel表格数据实例

    首先,我们介绍最常用的方法之一,即使用`System.Data.OleDb`命名空间中的`OleDbConnection`、`OleDbCommand`和`OleDbDataAdapter`类来读取Excel文件。这个方法基于Jet Engine,适用于旧版本的Excel(如97-2003)的....

    C++读取Excel数据

    在C++中,读取Excel数据通常涉及到使用OLE Automation(对象链接和嵌入自动化)技术,这是一种允许不同应用程序之间交互的方式。在这个特定的例子中,我们使用Microsoft Visual Studio 2003 MFC(Microsoft ...

    C# .net 读取excel文件所有表单(sheet)的名字,.txt文件,调用方法,使用需要引入System.Data.OleDb命名空间

    下面展示了一个名为`GetExcelTableName`的方法,该方法接受一个字符串参数`p_ExcelFile`,表示Excel文件的完整路径。此方法返回一个包含所有Sheet名称的`DataTable`对象。 ```csharp public static DataTable ...

    OleDb 的方式操作excel表

    * 4、对注册表的操作,解决读取Excel表格数据位数的限制【OperateRegedit】。 * 5、删除磁盘上指定的文件【ClearExcelFile】。 * 6、根据传入的Datatable数据源,生成Excel数据表...

    vb oledb连接excel2007

    VB 语言作为一种广泛应用于 Windows 平台的编程语言,经常用于开发各种 Windows 应用程序,而在数据交互方面,OLEDB 是一种非常常用的技术,特别是在连接 Excel 等外部数据源时。下面将详细介绍如何使用 VB 语言通过...

    C#excel导入报错Microsoft.ACE.OLEDB.12.0.rar

    在C#编程中,当你尝试从Excel文件读取数据或者将数据写入Excel时,可能会遇到“Microsoft.ACE.OLEDB.12.0”这个错误。这个问题通常出现在尝试使用ACE OLEDB提供程序(Access Database Engine)连接到Excel文件时,而...

    OLEDB驱动程序大全 MySQL-OleDB-Provider

    OLEDB驱动程序的工作原理是通过实现OLEDB接口,提供一套标准的方法和属性,使得任何支持OLEDB的应用程序都能够理解并操作数据。对于MySQL-OleDB-Provider,它实现了这些接口,使得.NET或其他支持OLEDB的程序能够执行...

    C#采用ADO.NET读取Excel 0307 数据不完整的问题

    在探讨"C#采用ADO.NET读取Excel 0307 数据不完整的问题"时,我们首先需要理解几个关键概念:ADO.NET、OLEDB、Excel文件的版本差异以及数据类型的自动识别机制。 ### ADO.NET与OLEDB ADO.NET是Microsoft提供的一套...

    OfficeExcel连接查询microsoft.ACE.oledb组件

    2. **连接字符串**:使用ACE.OLEDB组件时,你需要创建一个连接字符串来指定Excel文件的位置和访问方式。例如: ``` Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Path\To\Your\Workbook.xlsx;Extended ...

    Microsoft.ACE.OLEDB.12.0

    标题 "Microsoft.ACE.OLEDB.12.0" 指的是 Microsoft Office 兼容性包中的一个组件,它是用于连接和访问 Excel、Access 和其他 Office 文件的数据提供程序。这个提供程序允许开发者通过 OLEDB(对象链接和嵌入数据库...

Global site tag (gtag.js) - Google Analytics