網路上關於 C# 操作 Excel 的範例眾多,但真正能在生產環境穩定執行的不多。本文整理實務踩過的坑,針對 Microsoft.Office.Interop.Excel 的常見問題提供驗證過的解法。
using Microsoft.Office.Interop.Excel;
using System.Reflection;
public class MyConsole
{
public static void Main()
{
Application app = new ApplicationClass();
try
{
app.Visible = false;
Workbook wBook = app.Workbooks.Add(true);
Worksheet wSheet = wBook.Worksheets[1] as Worksheet;
wSheet.Cells[1, 1] = "this is a test";
app.DisplayAlerts = false;
app.AlertBeforeOverwriting = false;
wBook.Save();
app.Save(@"C:\abc.xls");
}
catch { }
finally
{
app.Quit();
app = null;
}
}
}
wBook.Worksheets[1] 才是第一個工作表,[0] 會拋出例外。新建活頁簿預設只有一張表;操作多張表建議用 new WorksheetClass() 後再 Add。開啟既有檔案時,改用 wBook.ActiveSheet 或先判斷張數較保險。
wBook.Save();
app.Save(@"C:\abc.xls");
缺一不可,否則會彈出「是否儲存」對話框導致無人值守失敗。
上述寫法在 Server 2003 下會在「我的文件」產生 Sheet1.xls 副本,abc.xls 變成捷徑,其他使用者無法開啟。解法:改用 SaveAs 直接另存新檔:
wSheet.SaveAs(@"C:\abc.xls", Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
wBook.Save();
如此不會產生副本,工作表名稱也會同步變更為 abc.xls。
app.Quit() 不保證立即釋放 COM 物件,Excel 進程常殘留。不建議用 KillProcess,可能誤殺使用者正在編輯的其他 Excel。目前最穩妥做法:
Quit() 前已完成所有 Save(),避免再跳儲存對話框。app = null 並呼叫 GC.Collect()、GC.WaitForPendingFinalizers() 兩次,強制 RCW 釋放。Application app = new Application();
try
{
app.Visible = false;
app.DisplayAlerts = false;
Workbook wb = app.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);
Worksheet ws = (Worksheet)wb.Worksheets[1];
ws.Cells[1, 1] = "測試資料";
ws.SaveAs(@"C:\Export\Report.xlsx", XlFileFormat.xlOpenXMLWorkbook,
Missing.Value, Missing.Value, Missing.Value, Missing.Value,
XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, Missing.Value);
wb.Close(true);
}
finally
{
app.Quit();
Marshal.ReleaseComObject(app);
app = null;
GC.Collect(); GC.WaitForPendingFinalizers();
GC.Collect(); GC.WaitForPendingFinalizers();
}
掌握索引起始值、雙重儲存、SaveAs 取代 Save、正確釋放 COM 物件四大要訣,即可讓 C# 操作 Excel 在伺服器端穩定運行。