方案一:Microsoft.ACE.OLEDB(傳統、無第三方套件)
必要條件
- 安裝 Microsoft Access Database Engine(32-bit 或 64-bit 需與應用程式集區位元數一致)。
- IIS 應用程式集區 啟用 32-bit 應用程式(若安裝 32-bit ACE)。
連接字串
.xls (Excel 97-2003):
Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties='Excel 8.0;HDR=YES;IMEX=1';
.xlsx (Excel 2007+):
Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1';
HDR=YES:第一列為標題。
IMEX=1:混合型別欄位以文字讀取,避免數值欄位讀成 null。
完整讀取程式碼
public DataTable ReadExcel(string filePath, string sheetName = "Sheet1") {
string ext = Path.GetExtension(filePath).ToLower();
string connStr = ext == ".xls"
? $"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={filePath};Extended Properties='Excel 8.0;HDR=YES;IMEX=1;'"
: $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={filePath};Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1;'";
using (var conn = new OleDbConnection(connStr)) {
conn.Open();
// 若不指定工作表,自動取第一個
if (string.IsNullOrEmpty(sheetName)) {
var schema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
sheetName = schema.Rows[0]["TABLE_NAME"].ToString();
}
string sql = $"SELECT * FROM [{sheetName}]";
using (var cmd = new OleDbCommand(sql, conn))
using (var adapter = new OleDbDataAdapter(cmd)) {
var dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}
繫結至 GridView
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
string file = Request.QueryString["filename"];
gvData.DataSource = ReadExcel(file);
gvData.DataBind();
}
}
方案二:EPPlus (OpenXML,推薦現代專案)
- 純 .NET 實作,不需安裝 Office / ACE 驅動,支援 .xlsx、.xlsm。
- NuGet:
Install-Package EPPlus(v5+ 需商業授權,v4.5.3.1 仍為 LGPL)。
EPPlus 讀取範例
public DataTable ReadExcelEPPlus(string filePath, string sheetName = null) {
using (var package = new ExcelPackage(new FileInfo(filePath))) {
var ws = string.IsNullOrEmpty(sheetName)
? package.Workbook.Worksheets[0]
: package.Workbook.Worksheets[sheetName];
var dt = new DataTable();
// 假設第一列為標題
foreach (var cell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
dt.Columns.Add(cell.Text);
for (int row = 2; row <= ws.Dimension.End.Row; row++) {
var dr = dt.NewRow();
for (int col = 1; col <= ws.Dimension.End.Column; col++)
dr[col - 1] = ws.Cells[row, col].Text;
dt.Rows.Add(dr);
}
return dt;
}
}
常見問題與解決
| 錯誤 | 原因 | 解決 |
| 'Microsoft.Jet.OLEDB.4.0' provider is not registered | 未安裝 ACE 或位元數不符 | 安裝對應版本 ACE;IIS 應用程式集區啟用 32-bit |
| External table is not in the expected format | 副檔名與連接字串不符(.xls 用 ACE 12.0) | 依副檔名切換 Provider |
| 欄位資料型別錯誤 | OLEDB 掃描前 8 列推斷型別 | 加 IMEX=1 強制文字;或在註冊表 TypeGuessRows=0 |
| 工作表名稱含空格/$ 符號 | SQL 需用方括號包裹 | SELECT * FROM [Sheet1$] 或 [Sheet Name$] |
匯出 DataTable 至 Excel
// EPPlus 匯出
public byte[] ExportExcel(DataTable dt, string sheetName = "Data") {
using (var pkg = new ExcelPackage()) {
var ws = pkg.Workbook.Worksheets.Add(sheetName);
ws.Cells.LoadFromDataTable(dt, true); // true = 含標題
return pkg.GetAsByteArray();
}
}
// 前端下載
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", "attachment;filename=Export.xlsx");
Response.BinaryWrite(ExportExcel(dt));
Response.End();
選型建議
- 舊系統 / 快速原型 / 僅 .xls:OLEDB 免安裝套件,但需處理驅動相容性。
- 新專案 / 雲端部署 / 高效能 / .xlsx:EPPlus / ClosedXML / NPOI 純 managed 程式碼,無相依性、效能佳、功能豐富(樣式、公式、圖表)。