<asp:FileUpload ID="FileUpload1" runat="server" Accept=".xls,.xlsx" />
<asp:Button ID="btnImport" runat="server" Text="匯入" OnClick="btnImport_Click" />
<asp:Label ID="lblMsg" runat="server" ForeColor="Red" />
protected void btnImport_Click(object sender, EventArgs e)
{
if (!FileUpload1.HasFile)
{
ShowAlert("請選擇 Excel 檔案");
return;
}
string ext = Path.GetExtension(FileUpload1.FileName).ToLower();
if (ext != ".xls" && ext != ".xlsx")
{
ShowAlert("僅支援 .xls 或 .xlsx 格式");
return;
}
// 1. 儲存暫存檔
string saveDir = Server.MapPath("~/UploadFiles/xls/");
if (!Directory.Exists(saveDir)) Directory.CreateDirectory(saveDir);
string savePath = Path.Combine(saveDir, Guid.NewGuid() + ext);
FileUpload1.SaveAs(savePath);
try
{
// 2. 讀取資料
DataSet ds = ReadExcel(savePath, "Sheet1"); // 或動態取得第一個工作表名稱
if (ds.Tables[0].Rows.Count == 0)
{
ShowAlert("Excel 內容為空");
return;
}
// 3. 逐筆處理
int success = 0, skip = 0, error = 0;
foreach (DataRow row in ds.Tables[0].Rows)
{
try
{
var student = new Student
{
Stuid = row["學號"]?.ToString().Trim(),
Stuname = row["姓名"]?.ToString().Trim(),
// 其他欄位對應...
};
if (string.IsNullOrEmpty(student.Stuid))
{ error++; continue; }
// 檢查重複
if (StudentBLL.Exists(student.Stuid))
{ skip++; continue; }
if (StudentBLL.Add(student)) success++;
else error++;
}
catch (Exception ex)
{
error++;
LogError(ex, row); // 記錄錯誤列內容供事後稽核
}
}
ShowAlert($"匯入完成:成功 {success} 筆、略過重複 {skip} 筆、錯誤 {error} 筆");
}
finally
{
// 4. 清理暫存檔
if (File.Exists(savePath)) File.Delete(savePath);
}
}
private DataSet ReadExcel(string filePath, string sheetName)
{
// .xls 使用 Jet OLEDB;.xlsx 需 ACE OLEDB (需安裝 Access Database Engine)
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;HDR=YES;IMEX=1;'";
using (var conn = new OleDbConnection(connStr))
using (var adapter = new OleDbDataAdapter($"SELECT * FROM [{sheetName}$]", conn))
{
var ds = new DataSet();
adapter.Fill(ds);
return ds;
}
}
private void ShowAlert(string msg)
{
ScriptManager.RegisterStartupScript(this, GetType(), "alert", $"alert('{msg.Replace("'", "\\'")}');", true);
}
| 項目 | 說明 |
|---|---|
| IMEX=1 | 混合資料型別欄位強制以文字讀取,避免數字欄位讀出 NULL。 |
| HDR=YES | 第一列視為標題,不納入資料。 |
| ACE vs Jet | .xlsx 必須用 ACE OLEDB 12.0/16.0,伺服器需安裝 Access Database Engine (64 位元版)。 |
| 暫存檔命名 | 使用 Guid 避免檔名衝突,匯入完成即刪除,不佔用空間。 |
| 去重策略 | 以業務鍵 (學號) 判斷,若需更新既有資料可改用 Upsert 模式。 |
OleDbDataReader 逐列讀取,避免一次載入整個 DataSet 佔記憶體。Excel 匯入看似簡單,實際上涉及檔案格式相容性、資料型別推斷、業務規則驗證、併發與錯誤處理等多層面。建立標準化的匯入流程與共用元件,能大幅降低維護成本並提升系統穩定度。