`
javatoyou
  • 浏览: 1016459 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Ado.Net操作Excel文件数据常见问题及解决

 
阅读更多

经常需要在数据 库与Execl之间互导数据 。net时代,ADO.NET可以使用使用Microsoft.Jet.OleDb访问访问Excel ,网上已经有很多类似的资源,最典型也是最简单的可能如下:(asp.net环境)

// 连接字符串
string xlsPath = Server.MapPath("~/app_data/somefile.xls"); // 绝对物理路径
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Extended Properties=Excel 8.0;" +
"data source=" + xlsPath;
// 查询语句
string sql = "SELECT * FROM [Sheet1$]";

DataSet ds = new DataSet();
OleDbDataAdapter da = new OleDbDataAdapter(sql, connStr);
da.Fill(ds); // 填充DataSet

// 在这里对DataSet中的数据 进行操作

// 输出,绑定数据
GridView1.DataSource = ds.Tables[0];
GridView1.DataBind();
很简单吧?!一切就像操作 数据 库一样,只是需要注意的是:
1。数据 提供程序使用Jet,同时需要指定Extended Properties 关键字设置 Excel 特定的属性,不同版本的Excel 对应不同的属性值: 用于 Extended Properties 值的有效 Excel 版本。
对于 Microsoft Excel 8.0 (97)、9.0 (2000) 和 10.0 (2002) 工作簿,请使用 Excel 8.0。

对于 Microsoft Excel 5.0 和 7.0 (95) 工作簿,请使用 Excel 5.0。

对于 Microsoft Excel 4.0 工作簿,请使用 Excel 4.0。

对于 Microsoft Excel 3.0 工作簿,请使用 Excel 3.0。

ref:http://msdn.microsoft.com /library/chs/default.asp?url=/library/CHS/dv_vbcode/html/vbtskcodeexamplereadingexceldataintodataset.asp

2。数据 源路径使用物理绝对路径(同Access)

3。如何引用表名?
Excel 工作簿中表(或范围)的有效引用。
若要引用完全使用的工作表的范围,请指定后面跟有美元符号的工作表名称。例如:

select * from [Sheet1$]
若要引用工作表上的特定地址范围,请指定后面跟有美元符号和该范围的工作表名称。例如:

select * from [Sheet1$A1:B10]
若要引用指定的范围,请使用该范围的名称。例如:

select * from [MyNamedRange]
ref:http://msdn.microsoft.com /library/chs/default.asp?url=/library/CHS/dv_vbcode/html/vbtskcodeexamplereadingexceldataintodataset.asp
说明:
可以引用Excel 工作簿中的三种对象:
• 整张工作表:[Sheet1$] ,Sheet1 就是工作表的名称
• 工作表上的命名单元格区域:[MyNamedRange] (不需要指定工作表,因为整个xls中命名区域只能唯一)
XLS命名方法:选中单元格范围》插入》名称》定义
• 工作表上的未命名单元格区域 :[Sheet1$A1:B10]
(在关系数据 库提供的各种对象中(表、视图、存储过程等),Excel 数据 源仅提供相当于表的对象,它由指定工作簿中的工作表和定义的命名区域组成。命名区域被视为“表”,而工作表被视为“系统表”)

注意:
•必须使用[](方括号),否将报:
FROM 子句语法错误
•必须跟$(美元符号),否则报:
Microsoft Jet 数据 库引擎找不到对象'Sheet2'。请确定对象是否存在,并正确地写出它的名称和路径。
•如果工作表名称不对,或者不存在,将报:
'Sheet2$' 不是一个有效名称。请确认它不包含无效的字符或标点,且名称不太长。
•在 如何在 Visual Basic 或 VBA 中使用 ADO 来处理 Excel 数据 中提到可以使用
~ 和 '(波浪线和单引号)代替[],使用ADO。NET测试没有成功,报:
FROM 子句语法错误
•当引用工作表明名([Sheet1$])时,数据 提供程序认为数据 表从指定工作表上最左上方的非空单元格开始。比如,工作表从第 3 行,C 列开始,第3行,C列之前以及第1、2行全为空,则只会显示从第3行,C列开始的数据 ;以最后表最大范围内的非空单元结束;
•因此,如需要精确读取范围,应该使用命名区域 [NamedRange],或者指定地址:[Sheet1$A1:C10]

4。如何引用列名?
•根据默认连接字符串中,数据 提供程序会将有效区域内的第一行作为列名,如果此行某单元格为空则用F1、F2表示,其中序数,跟单元格的位置一致,从1开始;
•如果希望第一行作为数据 显示,而非列名,可以在连接串的 Extended Properties 属性指定:HDR=NO
默认值为:HDR=NO 格式如下:

string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Extended Properties=""Excel 8.0;HDR=NO"";" +
"data source=" + xlsPath;
注意: Excel 8.0;HDR=NO 需要使用双引号(这里的反斜扛,是C#中的转义)

ref: ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.chs/WD_ADONET/html/745c5f95-2f02-4674-b378-6d51a7ec2490.htm 中 《连接Excel 》节(说明:在我自己的MSDN中,它的例子使用了两个双引号是错的,测试没有通过,原文这样说的:

注意,Extended Properties 所需的双引号必须还要加双引号。


在这种情况下,所有的列名都是以F开头,然后跟索引,从F1开始,F2,F3。。。。。。。

5。为什么有效单元格数据 不显示出来?
出现这种情况的可能原因是,默认连接中,数据 提供程序根据前面单元格推断后续单元个的数据 类型。
可以通过 Extended Properties 中指定 IMEX=1

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

PS:在baidu这个问题的时候,有网友说,将每个单元都加上引号,这固然是格方案,但是工作量何其大啊,又不零活,庆幸自己找到”治本药方“

more ref:
如何在 Visual Basic 或 VBA 中使用 ADO 来处理 Excel 数据
http://dotnet.aspx.cc/ShowDetail.aspx?id=C673E2CD-3F1E-4919-8CE0-D69B894A0599

注意:
在网上有很多同志说是加上HDR或IMEX这两个属性值后会报“找不到可安装的ISAM ”的错误。这时解决方法很简单:
就是把连接串写成如下形式:

Provider=Microsoft.Jet.Oledb.4.0;Data Source={0};Extended Properties='Excel 8.0;HDR=1; IMEX=1;' (注意红色标注的单引号)

而不要写成这样的形式:

Provider=Microsoft.Jet.Oledb.4.0;Data Source={0};Extended Properties=Excel 8.0;HDR=1; IMEX=1;

应用程序经常需要与Excel 进行数据 交互,在上一篇文章ADO.NET 如何读取 Excel (上)阐述了基于ADO.NET 读取Excel 的基本方法与技巧。今天这里要介绍是如何动态的读取Excel 数据 ,这里的动态指的是事先不知道Excel 文件的是什么样的结构,或者无法预测,比如一张.xls文件有多少张sheet,而且每张sheet的结构可能都不一样等等。
其实我们可以通过获取Excel 的“架构信息”来动态的构造查询语句。这里的“架构信息”与数据 库领域的“数据 库架构信息”意义相同(也称“元数据 ”),对于整个数据 库,这些“元数据 ”通常包括数据 库或可通过数据 库中的数据 源、表和视图得到的目录以及所存在的约束等;而对于数据 库中的表,架构信息包括主键、列和自动编号字段等。
在ADO.NET 如何读取 Excel (上)提到

在关系数据 库提供的各种对象中(表、视图、存储过程等),Excel 数据 源仅提供相当于表的对象,它由指定工作簿中的工作表和定义的命名区域组成。命名区域被视为“表”,而工作表被视为“系统表”)



这里我们将Excel 也当作一个“数据 库”来对待,然后利用OleDbConnection.GetOleDbSchemaTable 方法
要获取所需的架构信息,该方法获取的架构信息与ANSI SQl-92是兼容的:

注意:对于那些不熟悉 OLE DB 架构行集的人而言,它们基本上是由 ANSI SQL-92 定义的数据 库构造的标准化架构。每个架构行集具有为指定构造提供定义元数据 的一组列(称作 .NET 文档中的“限制列”)。这样,如果请求架构信息(例如,列的架构信息或排序规则的架构信息),则您会明确知道可以得到哪种类型的数据 。如果希望了解更多信息,请访问 Appendix B: Schema Rowsets。
ref:http://www.microsoft.com/china/msdn/library/office/office/odatanet2.mspx?mfr=true

以下是读取Excel 文件内“表”定义元数据 ,并显示出来的的程序片断:

// 读取Excel 数据 ,填充DataSet
// 连接字符串
string xlsPath = Server.MapPath("~/app_data/somefile.xls");
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Extended Properties=""Excel 8.0;HDR=No;IMEX=1"";" + // 指定扩展属性为 Microsoft Excel 8.0 (97) 9.0 (2000) 10.0 (2002),并且第一行作为数据 返回,且以文本方式读取
"data source=" + xlsPath;
string sql_F = "SELECT * FROM [{0}]";

OleDbConnection conn = null;
OleDbDataAdapter da = null;
DataTable tblSchema = null;
IList<string> tblNames = null;

// 初始化连接,并打开
conn = new OleDbConnection(connStr);
conn.Open();

// 获取数据 源的表定义元数据
//tblSchema = conn.GetSchema("Tables");
tblSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });

GridView1.DataSource = tblSchema;
GridView1.DataBind();

// 关闭连接
conn.Close();
GetOleDbSchemaTable 方法的详细说明可以参考:
http://msdn2.microsoft.com/zh-CN/library/system.data.oledb.oledbconnection.getoledbschematable.aspx

接着是一段利用“架构信息”动态读取Excel 内部定义的表单或者命名区域的程序片断:


// 读取Excel 数据 ,填充DataSet
// 连接字符串
string xlsPath = Server.MapPath("~/app_data/somefile.xls");
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Extended Properties=""Excel 8.0;HDR=No;IMEX=1"";" + // 指定扩展属性为 Microsoft Excel 8.0 (97) 9.0 (2000) 10.0 (2002),并且第一行作为数据 返回,且以文本方式读取
"data source=" + xlsPath;
string sql_F = "SELECT * FROM [{0}]";

OleDbConnection conn = null;
OleDbDataAdapter da = null;
DataTable tblSchema = null;
IList<string> tblNames = null;

// 初始化连接,并打开
conn = new OleDbConnection(connStr);
conn.Open();

// 获取数据 源的表定义元数据
//tblSchema = conn.GetSchema("Tables");
tblSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });

//GridView1.DataSource = tblSchema;
//GridView1.DataBind();

// 关闭连接
//conn.Close();

tblNames = new List<string>();
foreach (DataRow row in tblSchema.Rows) {
tblNames.Add((string)row["TABLE_NAME"]); // 读取表名
}

// 初始化适配器
da = new OleDbDataAdapter();
// 准备数据 ,导入DataSet
DataSet ds = new DataSet();

foreach (string tblName in tblNames) {
da.SelectCommand = new OleDbCommand(String.Format(sql_F, tblName), conn);
try {
da.Fill(ds, tblName);
}
catch {
// 关闭连接
if (conn.State == ConnectionState.Open) {
conn.Close();
}
throw;
}
}

// 关闭连接
if (conn.State == ConnectionState.Open) {
conn.Close();
}

// 对导入DataSet的每张sheet进行处理
// 这里仅做显示
GridView1.DataSource = ds.Tables[0];
GridView1.DataBind();

GridView2.DataSource = ds.Tables[1];
GridView2.DataBind();

// more codes
// .

这里我们就不需要对SELEC 语句进行“硬编码”,可以根据需要动态的构造FROM 字句的“表名”。

不仅可以,获取表明,还可以获取每张表内的字段名、字段类型等信息:


tblSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, null, null });

在ADO.nET 1.x 时候只有OleDb提供了GetOleDbSchemaTable 方法,而SqlClient或者OrcaleClient没有对应的方法,因为对应数据 库已经提供了类似功能的存储过程或者系统表供应用程序访问,比如对于Sql Server:

SELECT *
FROM Northwind.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'Customers'


而在ADO.NET 2.0中每个xxxConnenction都实现了基类System.Data.Common.DbConnection的 GetSchemal 方法
来获取数据 源的架构信息。
http://msdn2.microsoft.com/zh-cn/library/system.data.common.dbconnection.getschema.aspx

分享到:
评论

相关推荐

    asp.net知识库

    ADO.NET 2.0 大批量数据操作和多个动态的结果集 ADO.NET 2.0 异步处理 在ASP.NET中使用WINDOWS验证方式连接SQL SERVER数据库 改进ADO.Net数据库访问方式 ASP.NET 2.0 绑定高级技巧 简单实用的DataSet更新数据库的类+...

    Visual.Basic.2010.&.NET4.高级编程(第6版)-文字版.pdf

    10.2.1 ado.net的常见任务 393 10.2.2 ado.net的基本名称空间和类 398 10.2.3 ado.net组件 399 10.3 .net数据提供程序 400 10.3.1 connection对象 400 10.3.2 command对象 401 10.3.3 通过command对象...

    C#.net_经典编程例子400个

    267 6.5 复制文件 268 实例186 移动正在使用的文件 268 实例187 批量复制文件 269 6.6 指定类型的文件操作 270 实例188 文本文件的操作 270 实例189 简单的文件加密解密 271 6.7 ...

    C#程序开发范例宝典(第2版).part13

    实例232 获取文件夹下的所有文件夹及文件的名称 321 第7章 操作系统与Windows相关程序 324 7.1 启动相关 325 实例233 进入Windows系统前发出警告 325 实例234 实现注销、关闭和重启计算机 326 7.2 获得磁盘...

    C#程序开发范例宝典(第2版).part08

    实例232 获取文件夹下的所有文件夹及文件的名称 321 第7章 操作系统与Windows相关程序 324 7.1 启动相关 325 实例233 进入Windows系统前发出警告 325 实例234 实现注销、关闭和重启计算机 326 7.2 获得磁盘...

    C#程序开发范例宝典(第2版).part02

    实例232 获取文件夹下的所有文件夹及文件的名称 321 第7章 操作系统与Windows相关程序 324 7.1 启动相关 325 实例233 进入Windows系统前发出警告 325 实例234 实现注销、关闭和重启计算机 326 7.2 获得磁盘...

    C#程序开发范例宝典(第2版).part12

    实例232 获取文件夹下的所有文件夹及文件的名称 321 第7章 操作系统与Windows相关程序 324 7.1 启动相关 325 实例233 进入Windows系统前发出警告 325 实例234 实现注销、关闭和重启计算机 326 7.2 获得磁盘...

    PSIS:用于 SqlServer 的基于 Powershell 的工具 - 并行批量加载、并行星型模式填充、数据库源控制和迁移

    项目介绍 一组针对ETL (提取转换和加载)任务以及数据库版本...通过 ADO.Net 来自 Excel 从 IEnumberable 单通道、多线程星型模式填充器 将数据提取到 .csv 文件 遵循构建和部署功能 提取代码 部署代码和更改文件

    Visual Basic 2010入门经典.part1.rar

    2.6.1 使用“解决方案资源管理器”管理项目文件 47 2.6.2 使用解决方案 48 2.6.3 理解项目组件 49 2.6.4 设置项目属性 50 2.6.5 添加和删除项目文件 50 2.7 快速而简单的编程入门指南 51 2.7.1 用变量存储值 ...

    Visual Basic 2010入门经典.part2.rar

    2.6.1 使用“解决方案资源管理器”管理项目文件 47 2.6.2 使用解决方案 48 2.6.3 理解项目组件 49 2.6.4 设置项目属性 50 2.6.5 添加和删除项目文件 50 2.7 快速而简单的编程入门指南 51 2.7.1 用变量存储值 ...

Global site tag (gtag.js) - Google Analytics