网站建设费用怎么记账,铜仁网站建设哪家专业,内蒙古app开发公司,怎样做一个网站平台1 引言 在应用程序的设计中#xff0c;经常需要读取Excel数据或将Excel数据导入转换到其他数据载体中#xff0c;例如将Excel数据通过应用程序导入SQL Sever等数据库中以备使用。笔者在开发“汽车产业链ASP协同商务平台”中遇到了类似需求。某汽车整车生产企业需要将其车…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; DataSourcef:/test.xls;Extended PropertiesExcel 8.0;HDRYES;; OleDbConnection Connnew OleDbConnection(ConnStr); Conn.Open(); string SQLselect * from [sheet1$]; OleDbDataAdapter danew OleDbDataAdapter(SQL,ConnStr); DataSet dsnew DataSet(); da.Fill(ds); DataGrid1.DataSourceds; DataGrid1.DataBind(); Conn.Close(); 但是运行以上代码的结果并不是期望的它将显示为表2所示的内容。可以发现第一个字段中为“1042”的两个数据项变为空。 表2 DataGrid1所显示的数据内容 有程序设计人员将以上代码OleDbConnection连接字符串中的Extended Properties一项作了如下改动Extended PropertiesExcel 8.0;HDRNO;IMEX1’认为可以解决此问题。由于在开发“汽车产业链协同商务平台”中碰到过类似问题作了大量的测试后发现添加IMEX1后并未实质上解决此问题。表现为如果某字段前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三种分别代表导出、导入、混合模式。当我们设置IMEX1时将强制混合数据转换为文本但仅仅这种设置并不可靠IMEX1只确保在某列前8行数据至少有一个是文本项的时候才起作用它只是把查找前8行数据中数据类型占优选择的行为作了略微的改变。例如某列前8行数据全为纯数字那么它仍然以数字类型作为该列的数据类型随后行里的含有文本的数据仍然变空。 另一个改进的措施是IMEX1与注册表值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 tablenew DataTable(auto); DataRow rownull; StreamReader srnew StreamReader(c:/auto.csv,System.Text.Encoding.Default); //创建与数据源对应的数据列 line sr.ReadLine(); splitline.Split(,); foreach(String colname in split){ table.Columns.Add(colname,System.Type.GetType(System.String)); } //将数据填入数据表 int j0; while((linesr.ReadLine())!null){ j0; row table.NewRow(); splitline.Split(,); foreach(String colname in split){ row[j]colname; j;} table.Rows.Add(row);} sr.Close(); //显示数据 dataGrid1.DataSourcetable.DefaultView; dataGrid1.DataBind(); 说明按照上面这篇文章分析当某列数据中含有混合类型时在.NET中使用Microsoft.Jet.OLEDB.4.0来读取Excel文件造成数据丢失是不可避免的
当IMEX1与注册表值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程序就会默认行数为最大