zoukankan      html  css  js  c++  java
  • .NET中EXCEL数据访问数据丢失的分析与终极解决方案

    Excel是Microsoft公司的电子表格处理软件,在现代办公及企业信息化的应用中使用非常广泛,相信不少朋友都会碰到跟我一样的困扰,现将终极解决方案记录如下,希望对同行朋友也有所帮助
     
    1 问题描述
        Excel是Microsoft公司的电子表格处理软件,在现代办公及企业信息化的应用中使用非常广泛,正因如此,在程序设计中我们经常要通过访问Excel文件来获得数据,但Excel文件不是标准数据库[1]。
        ASP.NET也是Microsoft公司的产品,作为.NET FrameWork框架中的一个重要组成部分,其主要用于Web设计。我们在.NET中访问读取Excel数据时一般采用Microsoft.Jet.OLEDB.4.0[2]。现以读取一个Excel文件auto.xls中sheet1工作表为例,工作表的内容如表1所示。 


        现将该表的数据内容读取并显示到到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所示的内容。可以发现第二个字段中以“CE”开头的数据项变为空。  
     

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

    2 问题分析
        产生这种问题的根源与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驱动的这种机制还是让这列的数据变成空。 

    3 解决方法
        从以上的分析中可以得知,当某列数据中含有混合类型时,在.NET中使用Microsoft.Jet.OLEDB.4.0来读取Excel文件造成数据丢失是不可避免的,要解决这个问题只能考虑采用其它数据读取方法。
        在.NET中读取Excel文件的另外一种方法是回到使用传统COM组件,这种方法在很多技术文章或论文中都有涉及,本文不作赘述。需要指出的是,使用COM组件来读取Excel文件数据的效率较低,在作释放的时候有可能碰到不可预知的错误,特别开发Web应用的程序应该慎重使用。  
    本文提出另外一种利用读取CSV纯文本格式解决此问题的方法。
        (1)在读取Excel的.xls类型的文本数据之前,先将其转换为.csv格式,在Excel中直接另存为这种格式就可以达到转换的目的。CSV文件又称为逗号分隔的文件,是一种纯文本文件,它以“,”分隔数据列,本文表1的数据表用CSV格式存储后用纯文本编辑器打开的表现形式如表3所示。  

        需要指出的是,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(fileName, System.Text.Encoding.Default);   //创建与数据源对应的数据列   
                line = sr.ReadLine();   
                split=line.Split(',');
                foreach(String colname in split)
                {
                    table.Columns.Add(colname.ToString(),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();

    4 结语
        在应用程序的设计中,需要访问Excel数据的情况非常普遍,本文以在.NET中对访问含有混合类型数据的Excel表格拟采取的方法进行探讨。当然,如果不存在混合类型的数据使用Microsoft.Jet.OLEDB为较佳方案。对于不是使用.NET开发的情况,本论文的分析和所提供的方法亦可参考。
  • 相关阅读:
    windows ntstatus.h 头文件
    Android Q 后台启动 Activity
    windows 删除文件夹所有文件夹及文件代码
    Android 加壳App Demo
    Android App 签名保护demo
    RXAndroidBle 记录网址
    c++ windows 获取系统时间
    js 代码保存
    day33 ansible
    day31 综合实时同步服务
  • 原文地址:https://www.cnblogs.com/robinli/p/2119676.html
Copyright © 2011-2022 走看看