System.Data.OleDb、Microsoft Jet OLEDB 4.0 Providerpublic static DataTable ExcelToDataTable(string filePath, string sheetName)
{
// Excel 97-2003 (.xls) 連接字串
string connStr = $@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={filePath};Extended Properties='Excel 8.0;HDR=YES;IMEX=1;'";
// Excel 2007+ (.xlsx) 需改用 ACE Provider:
// string connStr = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={filePath};Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1;'";
string query = $"SELECT * FROM [{sheetName}$]"; // 工作表名需加 $ 符號
using (OleDbConnection conn = new OleDbConnection(connStr))
using (OleDbDataAdapter adapter = new OleDbDataAdapter(query, conn))
{
DataTable dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
關鍵參數說明:
HDR=YES:第一行為標題列;HDR=NO 則視為資料,欄位名自動產生 F1、F2...。IMEX=1:混合模式,強制將混合型態欄位視為文字讀取,避免數值欄位前幾行為數字後面出現文字導致讀取為 NULL。public static void DataTableToAccess(DataTable dt, string accessConnStr)
{
string sql = "INSERT INTO tb_ExcelData (strColumn1, fColumn2) VALUES (@p1, @p2)";
using (OleDbConnection conn = new OleDbConnection(accessConnStr))
using (OleDbCommand cmd = new OleDbCommand(sql, conn))
{
// 參數化查詢防注入、處理型別轉換
cmd.Parameters.Add("@p1", OleDbType.VarWChar, 50);
cmd.Parameters.Add("@p2", OleDbType.Double);
conn.Open();
foreach (DataRow row in dt.Rows)
{
cmd.Parameters["@p1"].Value = row[0]?.ToString() ?? string.Empty;
cmd.Parameters["@p2"].Value = Convert.ToDouble(row[1] ?? 0);
cmd.ExecuteNonQuery();
}
}
}
public static void ImportExcelToDb(string excelPath, string sheetName, string targetConnStr)
{
DataTable dt = ExcelToDataTable(excelPath, sheetName);
DataTableToAccess(dt, targetConnStr); // 或改寫為 SqlConnection 寫入 SQL Server
}
OleDbDataAdapter.UpdateBatchSize 或 SqlBulkCopy (SQL Server 專用) 替換逐筆 ExecuteNonQuery,效能提升 10-100 倍。TransactionScope 或 OleDbTransaction 中,失敗回滾保證資料一致性。| 錯誤現象 | 原因 | 解決方案 |
|---|---|---|
External table is not in the expected format | Provider 版本不匹配 (.xls 用 Jet, .xlsx 用 ACE) | 依副檔名切換 Provider,確認目標機器已安裝對應 Access Database Engine (32/64 位元需與應用程式一致) |
| 數值欄位讀出為 NULL | 前 8 行 (預設掃描範圍) 為數字,後出現文字 | 連接字串加 IMEX=1;或修改註冊表 TypeGuessRows=0 掃描全表 |
| 中文欄位名亂碼/錯誤 | OleDb 不支援中文欄位名稱當參數 | 查詢時用別名 SELECT [中文欄位] AS Col1,或程式端用索引 row[0] 存取 |
| 伺服器部署失敗 | IIS 應用程式集區啟用 32 位元應用程式設定不匹配 | 應用程式集區 → 進階設定 → 啟用 32 位元應用程式 = True (若安裝 32-bit ACE) |
新專案建議使用 ClosedXML、EPPlus (商業需授權) 或 NPOI 純 .NET 程式庫直接解析 .xlsx (OpenXML 格式),無需安裝 Office/ACE 驅動程式,支援 Linux/Docker 容器化部署,記憶體佔用更可控,語法更現代化:
// EPPlus 範例
using (var package = new ExcelPackage(new FileInfo("data.xlsx")))
{
var ws = package.Workbook.Worksheets[0];
foreach (var row in ws.Cells[2, 1, ws.Dimension.End.Row, ws.Dimension.End.Column].Rows)
{
var col1 = row[0].Text;
var col2 = row[1].GetValue<double>();
// 直接寫入 DB...
}
}