核心方法比較
| 方法 | 用途 | 是否變更原檔 | 適用場景 |
Workbook.Save() | 覆寫原檔 | 是 | 已有檔案路徑,單純存檔 |
Workbook.SaveAs() | 另存新檔/轉檔 | 否 (建立新檔) | 指定新路徑、新格式、密碼、存取模式 |
Workbook.SaveCopyAs() | 備份副本 | 否 (原檔維持開啟/未修改) | 建立備份、輸出唯讀副本、不觸發 BeforeSave 事件 |
SaveAs 完整參數簽名
public void SaveAs(
object Filename, // 新檔案完整路徑
object FileFormat = Type.Missing, // XlFileFormat 常數
object Password = Type.Missing, // 開啟密碼 (字串,區分大小寫,最長 15 字)
object WriteResPassword = Type.Missing, // 寫入保護密碼
object ReadOnlyRecommended = Type.Missing, // 建議唯讀 (true/false)
object CreateBackup = Type.Missing, // 建立備份檔 (.xlk)
object AccessMode = Type.Missing, // XlSaveAsAccessMode: xlExclusive(1)/xlNoChange(2)/xlShared(3)
object ConflictResolution = Type.Missing, // xlUserResolution(1)/xlLocalSessionChanges(2)/xlOtherSessionChanges(3)
object AddToMru = Type.Missing, // 加入最近使用清單 (true/false)
object TextCodepage = Type.Missing, // 文字檔編碼代碼頁
object TextVisualLayout = Type.Missing // 文字檔視覺配置
);
常用檔案格式常數 (XlFileFormat)
xlOpenXMLWorkbook = 51 // .xlsx (預設,Office 2007+)
xlOpenXMLWorkbookMacroEnabled = 52 // .xlsm (含巨集)
xlExcel12 = 50 // .xlsb (二進位,載入快、檔案小)
xlExcel8 = 56 // .xls (Excel 97-2003 相容)
xlCSV = 6 // .csv (逗點分隔,依系統地區設定)
xlText = -4158 // .txt (定寬/分隔)
xlHtml = 44 // .htm/.html
xlXMLSpreadsheet = 46 // .xml (Excel 2003 XML)
xlTemplate = 17 // .xltx (範本)
xlTemplate8 = -4143 // .xlt (舊版範本)
實用儲存範例
1. 基本另存為 .xlsx
wb.SaveAs(@"C:\Output\Report.xlsx", Excel.XlFileFormat.xlOpenXMLWorkbook);
2. 另存為 .xls (相容舊版)
wb.SaveAs(@"C:\Output\Report.xls", Excel.XlFileFormat.xlExcel8);
3. 設定密碼與唯讀建議
wb.SaveAs(
Filename: @"C:\Output\Secret.xlsx",
FileFormat: Excel.XlFileFormat.xlOpenXMLWorkbook,
Password: "OpenPwd123", // 開啟需密碼
WriteResPassword: "WritePwd456", // 修改需密碼 (唯讀模式可不輸入)
ReadOnlyRecommended: true); // 開啟時提示「建議唯讀」
4. 共用活頁簿 (多人同時編輯,舊版功能)
wb.SaveAs(
Filename: @"C:\Shared\Team.xlsx",
AccessMode: Excel.XlSaveAsAccessMode.xlShared,
ConflictResolution: Excel.XlSaveConflictResolution.xlUserResolution);
5. 儲存為 CSV (指定編碼 UTF-8)
// Interop 儲存 CSV 會依系統地區設定決定分隔符與編碼 (通常 ANSI)
// 若需 UTF-8 建議改用 StreamWriter 或 EPPlus
wb.SaveAs(@"C:\Output\Data.csv", Excel.XlFileFormat.xlCSV);
6. SaveCopyAs 建立唯讀備份
// 原檔維持開啟狀態,不觸發 BeforeSave、AfterSave 事件
wb.SaveCopyAs(@"C:\Backup\Report_Backup_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".xlsx");
完整封裝方法
public enum ExcelFormat { Xlsx, Xlsm, Xlsb, Xls, Csv, Pdf }
public static class ExcelExtensions
{
public static void SaveAs(this Excel.Workbook wb, string path, ExcelFormat format,
string openPassword = null, string writePassword = null, bool readOnlyRecommended = false)
{
var xlFormat = format switch
{
ExcelFormat.Xlsx => Excel.XlFileFormat.xlOpenXMLWorkbook,
ExcelFormat.Xlsm => Excel.XlFileFormat.xlOpenXMLWorkbookMacroEnabled,
ExcelFormat.Xlsb => Excel.XlFileFormat.xlExcel12,
ExcelFormat.Xls => Excel.XlFileFormat.xlExcel8,
ExcelFormat.Csv => Excel.XlFileFormat.xlCSV,
ExcelFormat.Pdf => Excel.XlFileFormat.xlTypePDF, // 需 Excel 2010+ 或增益集
_ => Excel.XlFileFormat.xlOpenXMLWorkbook
};
wb.SaveAs(
Filename: path,
FileFormat: xlFormat,
Password: openPassword ?? Type.Missing,
WriteResPassword: writePassword ?? Type.Missing,
ReadOnlyRecommended: readOnlyRecommended,
AccessMode: Excel.XlSaveAsAccessMode.xlExclusive, // 獨佔模式最安全
ConflictResolution: Excel.XlSaveConflictResolution.xlLocalSessionChanges
);
}
// 另存為 PDF (Excel 2010+ 內建)
public static void ExportAsPdf(this Excel.Workbook wb, string path)
{
wb.ExportAsFixedFormat(
Type: Excel.XlFixedFormatType.xlTypePDF,
Filename: path,
Quality: Excel.XlFixedFormatQuality.xlQualityStandard,
IncludeDocProperties: true,
IgnorePrintAreas: false,
OpenAfterPublish: false);
}
}
常見問題與解決
| 問題 | 原因 | 解決 |
| 儲存時彈出「檔案已存在」對話框 | DisplayAlerts = true (預設) | 儲存前設定 excel.DisplayAlerts = false; |
| 存取被拒絕 / 檔案被鎖定 | 檔案被其他程式開啟、權限不足、網路磁碟延遲 | 檢查檔案鎖定、使用 FileShare.ReadWrite、重試機制 |
| 儲存 .xls 時資料遺失 (超過 65535 列) | .xls 列數限制 65,536 | 改用 .xlsx (1,048,576 列) 或分割多工作表 |
| CSV 中文亂碼 | Interop CSV 使用系統 ANSI 編碼 | 改用 StreamWriter 寫入 UTF-8、或 EPPlus |
| COMException 0x800A03EC | 未知錯誤,常見於路徑無效、格式不支援、記憶體不足 | 檢查路徑、磁碟空間、檔案格式相容性 |
無 Excel 環境替代方案
// EPPlus (商業授權) - 純 .NET 寫入 .xlsx
using (var pkg = new ExcelPackage(new FileInfo("template.xlsx")))
{
var ws = pkg.Workbook.Worksheets["Sheet1"];
ws.Cells["A1"].Value = "Hello";
pkg.SaveAs(new FileInfo("output.xlsx"));
}
// ClosedXML (MIT) - 簡潔 API
using (var wb = new XLWorkbook("template.xlsx"))
{
wb.Worksheet("Sheet1").Cell("A1").Value = "Hello";
wb.SaveAs("output.xlsx");
}
// NPOI - 支援 .xls/.xlsx
var wb = new XSSFWorkbook(); // .xls 用 HSSFWorkbook
var ws = wb.CreateSheet("Sheet1");
ws.CreateRow(0).CreateCell(0).SetCellValue("Hello");
using (var fs = File.Create("output.xlsx")) wb.Write(fs);
最佳實務清單
- [ ] 明確指定
FileFormat 避免依賴副檔名推斷
- [ ] 使用
xlExclusive 存取模式減少衝突
- [ ] 儲存前關閉
DisplayAlerts、ScreenUpdating
- [ ]
finally 區塊確實 wb.Close()、excel.Quit()、Marshal.ReleaseComObject
- [ ] 伺服器端/容器部署**禁止使用 Interop**,改用 EPPlus/ClosedXML
- [ ] 大量資料寫入用陣列
Range.Value2 = object[,] 而非逐 Cell