應用程序經常需要與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。
以下是讀取Excel文件內“表”定義元數據,并顯示出來的的程序片斷:

Code
// 讀取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();
接著是一段利用“架構信息”動態讀取Excel內部定義的表單或者命名區域的程序片斷:

Code
xcel數據,填充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 字句的“表名”。
不僅可以,獲取表明,還可以獲取每張表內的字段名、字段類型等信息:

Code
tblSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, null, null });
在ADO.nET 1.x 時候只有OleDb提供了GetOleDbSchemaTable 方法,而SqlClient或者OrcaleClient沒有對應的方法,因為對應數據庫已經提供了類似功能的存儲過程或者系統表供應用程序訪問,比如對 于Sql Server:

Code
SELECT *
FROM Northwind.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'Customers'
而在ADO.NET 2.0中每個xxxConnenction都實現了基類
System.Data.Common.DbConnection的 GetSchemal 方法
來獲取數據源的架構信息。