利用 Microsoft.Jet.OLEDB.4.0 Provider,ADO.NET 可像操作資料庫一樣讀寫 Excel。但 Excel 非真關聯資料庫,存在格式、公式、主鍵、型別推斷等固有限制,需掌握關鍵技巧方能得心應手。
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Extended Properties='Excel 8.0;HDR=YES;IMEX=1';" +
"Data Source=" + xlsPath;
| 參數 | 說明 | 建議值 |
|---|---|---|
| Excel 版本 | Extended Properties 版本號 | Excel 8.0 適用 97/2000/2002/2003 |
| HDR | 首列是否為欄位名 | YES(預設)/NO(首列為資料) |
| IMEX | 混合型別欄位處理 | 1=強制視為文字,避免型別推斷導致資料遺失 |
[Sheet1$]($ 為必需,方括號必需)[Sheet1$A1:C10](精確控制讀寫區域)[MyNamedRange](跨工作表唯一,最彈性)注意:[Sheet1$] 從左上角第一非空儲存格開始,到右下角最後非空儲存格結束。精確讀取請用範圍或命名區域。
HDR=YES:首列內容為欄名,空儲存格自動命名 F1、F2…HDR=NO:所有欄名為 F1、F2、F3…| 限制 | 影響 | 對策 |
|---|---|---|
| 無法設定儲存格格式 | 插入列自動繼承上列格式 | 預先在樣板檔設好格式,或改用 Open XML SDK/EPPlus |
| 無法寫入公式 | 公式字串會當文字存入 | 同上,改用 Open XML SDK |
| Jet 無法提供主鍵/索引 | CommandBuilder 無法自動生成 Update/Insert | 手寫 SQL 命令,或改用 ACE Provider + 主鍵欄位 |
| 型別推斷錯誤 | 數字/文字混雜欄位資料遺失 | IMEX=1 強制文字模式 |
| 唯讀/權限/鎖定問題 | 更新/刪除失敗 | 確保檔案非唯讀、獨佔開啟、ASP.NET 執行身分有寫入權限 |
OleDbConnection conn = new OleDbConnection(connStr);
conn.Open();
// 1. 取得所有「表」(工作表+命名區域)
DataTable schema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,
new object[] { null, null, null, "TABLE" });
List tables = new List();
foreach (DataRow row in schema.Rows)
tables.Add((string)row["TABLE_NAME"]);
// 2. 逐表填充 DataSet
OleDbDataAdapter da = new OleDbDataAdapter();
DataSet ds = new DataSet();
foreach (string t in tables) {
da.SelectCommand = new OleDbCommand($"SELECT * FROM [{t}]", conn);
da.Fill(ds, t);
}
// 3. 取得指定表欄位結構
DataTable colSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns,
new object[] { null, null, "Sheet1$", null });
// colSchema 含 COLUMN_NAME, DATA_TYPE, ORDINAL_POSITION 等
protected void DoOleSql(string sql, string xlsFile)
{
string connStr = $"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={Server.MapPath(xlsFile)};Extended Properties='Excel 8.0;HDR=NO;IMEX=0'";
using (OleDbConnection conn = new OleDbConnection(connStr))
{
conn.Open();
using (OleDbCommand cmd = new OleDbCommand(sql, conn))
{
cmd.ExecuteNonQuery();
}
}
}
// 使用範例
DoOleSql("SELECT * FROM [Sheet1$]", "test.xls");
DoOleSql("UPDATE [Sheet1$] SET F1='333' WHERE F2='b3'", "test.xls");
DoOleSql("INSERT INTO [Sheet1$] (F1,F2) VALUES ('a','b')", "test.xls");
// 非標準結構指定範圍
DoOleSql("SELECT * FROM [Sheet1$A3:F20]", "test.xls");