OLDB读取excel的数据类型不匹配的解决方案(ZT)
在应用程序的设计中,经常需要读取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=c:/auto.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();
5 结语
在应用程序的设计中,需要访问Excel数据的情况非常普遍,本文以在.NET中对访问含有混合类型数据的Excel表格拟采取的方法进行探讨。当然,如果不存在混合类型的数据使用Microsoft.Jet.OLEDB为较佳方案。对于不是使用.NET开发的情况,本论文的分析和所提供的方法亦可参考。
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_MACHINE\SOFTWARE\Microsoft \Jet\4.0\Engines\Excel”下的该注册表值来更改采样行数。但是这种改进还是没有根本上解决问题,即使我们把IMEX设为“1”, TypeGuessRows设得再大,例如1000,假设数据表有1001行,某列前1000行全为纯数字,该列的第1001行又是一个文本,ISAM驱动的这种机制还是让这列的数据变成空。
OLDB读取excel的数据类型不匹配的解决方案(ZT)的更多相关文章
- C#读取Excel的数据,并且以混合模式读取,防止数据类型变更
/// <summary> /// Read Excel to DataSet /// </summary> /// <param name="filename ...
- 深入理解pandas读取excel,txt,csv文件等命令
pandas读取文件官方提供的文档 在使用pandas读取文件之前,必备的内容,必然属于官方文档,官方文档查阅地址 http://pandas.pydata.org/pandas-docs/versi ...
- EasyExcel 轻松灵活读取Excel内容
写在前面 Java 后端程序员应该会遇到读取 Excel 信息到 DB 等相关需求,脑海中可能突然间想起 Apache POI 这个技术解决方案,但是当 Excel 的数据量非常大的时候,你也许发现, ...
- Open Xml 读取Excel中的图片
在我的一个项目中,需要分析客户提供的Excel, 读出其中的图片信息(显示在Excel的第几行,第几列,以及图片本身). 网络上有许多使用Open Xml插入图片到Word,Excel的文章, 但 ...
- C# ASP.NET 读取EXCEL 单元格 读取 空值 不显示
跟大家分享一下,[摘自]:http://blog.csdn.net/li185416672/article/details/8213729 读取excel时,某些单元格为空值 原来如此: 当我们用ol ...
- .Net读取Excel文件时丢失数据的问题 (转载)
相信很多人都试过通过OleDB读取Excel文件,这种方法效率十分高,只是有一点会让人十分头痛,就是当一列中既有混合型数据,又有纯数据时,往往容易丢失数据. 百度过后,改连接字符串 “HDR=YES; ...
- C#读取Excel文件:通过OleDb连接,把excel文件作为数据源来读取
转载于:http://developer.51cto.com/art/200908/142392.htm C#读取Excel文件可以通过直接读取和OleDb连接,把excel文件作为数据源来读取: ...
- PHP读取excel文档
PHP读取excel文档 项目需要读取Excel的内容,从百度搜索了下,主要有两个选择,第一个是PHPExcelReader,另外一个是PHPExcel. PHPExcelReader比较轻量级, ...
- C# conn.open() 外部表不是预期的格式( 读取EXCEL文件出错)
环境:win7+iis7+Office2007 在asp.net网站中导出Excel文件后,再把文件导入到数据库中. 读取Excel文件时,打开连接出错. 错误为:外部表不是预期的格式 解决:检查了一 ...
随机推荐
- xlwt写入中文操作不成功,提示UnicodeDecodeError: ascii codec can't decode byte ...
打开xlwt包里的Workbook.py文件,修改Workbook类的__init__方法 将 def __init__(self, encoding='ascii', style_compressi ...
- HTML之iframe
iframe:是框架的一种形式. 属性: frameborder=0/1 表示是否显示周围边框 0--否 1--是 width,height:设置的边框宽高,具体数值不需要加单位,也可用百分比 mar ...
- AJAX请求WebService
1.WebService代码 [WebMethod] [ScriptMethod(UseHttpGet = false)] public string GetObject() { User user ...
- Maven Test
Failures表示要测试的结果与预期值不一致:Errors表示测试代码或产品代码发生了未预期的错误:Skipped表示那些被标记为忽略的测试方法.在Junit中用户可以使用@Ignore注解标记忽略 ...
- unity文件解析以及版本控制
刚开始使用unity做开发时,拿到一个范例工程先上传SVN,之后再自己做一些修改后,发现有非常多文件都有变化,这才知道有很多本地生成的文件,是不用上传的,但是不知道哪些才是需要共用的.之后又困扰于修改 ...
- Javascript 事件对象(三)事件冒泡
事件流---事件冒泡取消冒泡:ev.cancelBubble=true ---事件捕获Ie下是没有的,在绑定事件中,标准下是有的 <!DOCTYPE HTML> <html> ...
- 世界超强完美DIY 电子奇才五年全手工制作CPU
世界超强完美DIY 电子奇才五年全手工制作CPU 2015-07-08 极客范 (点击上方公众号,可快速关注我们) 在如今越来越靠程序化.流水线作业来完成生产的制造业中,想找一件手工打造的产品,真是越 ...
- MySQL数据库在linux的安装,编程与操作
一.安装 ubuntu上安装MySQL非常简单只需要几条命令就可以完成. 1. sudo apt-get install mysql-server 2. apt-get isntall mysql ...
- 安卓四大组件之activity和获取网络资源之断点续传
Day05 数据存储及多线程断点续传1.数据提交到服务器两种方式的优缺点* GET请求优点:使用非常方便,只需要在url后面组拼数据.缺点:数据在url的后面组拼,不安全.有数据长度限制.* POST ...
- 安装和使用Visual Studio 2013并进行简单的单元测试
现在我正在安装visual studio 2013,我听说好多同学都在安装visual studio 2015,但是他好像只支持Win10吧,我就退而求其次安装了visual studio 2013. ...