跳過到頁腳內容
使用 IRONXL

發布Excel物件C# | 使用IronXL停止殘留的Excel進程

釋放 Excel 物件 C#:使用IronXL停止殘留的 Excel 流程:圖 1 - 釋放 Excel 物件 C#:兩種方法的比較

在 C# 應用程式中處理 Microsoft Excel 檔案時,經常會遇到一個令人沮喪的問題:Excel 進程拒絕關閉。 您可能會發現工作管理員中累積了多個 EXCEL.EXE 實例,即使您的程式碼已執行完畢,它們仍然會佔用大量記憶體。 本指南解釋了為什麼傳統的 Excel 互通會出現這種情況,並演示了IronXL如何徹底消除這些 COM 物件難題——讓您免受複雜的清理程式碼和生產記憶體洩漏的困擾。

根本原因在於.NET Framework透過 COM 引用與 Microsoft Office 的互動方式。 當您使用 Microsoft.Office.Interop.Excel 編寫程式碼時,每個 Excel 應用程式物件、工作簿和工作表都會建立 COM 對象,這些物件需要明確清理。即使漏掉一個釋放調用,或使用類似 app.Workbooks.Open() 這樣的雙點模式,都會留下孤立引用,導致 Excel 進程無法終止。

立即開始在您的項目中使用 IronXL 並免費試用。

第一步:
green arrow pointer

為什麼關閉Excel後,工作管理員中仍然會保留Excel進程?

由於 COM 物件參考計數未正確遞減,Excel 應用程式無法終止。 每次您的程式碼存取 Excel 應用程式、工作簿或工作表時,執行時間都會建立一個執行時間可呼叫包裝器 (RCW),其中包含對底層 COM 物件的參考計數。 .NET垃圾回收器無法釋放這些互通對象,直到使用 Marshal.ReleaseComObject 明確釋放每個引用為止。

導致流程停滯不前的常見錯誤包括:

  • 在屬性鏈中使用兩個點,例如 app.Workbooks.Open()(這會建立隱藏的臨時物件)
  • 使用 foreach 循環遍歷 COM 集合(這將產生未發布的枚舉器)
  • 忘記在 Excel 應用程式物件上呼叫 Quit()
  • finally 程式碼區塊中捕獲異常而不進行清理

在早期版本的 Microsoft Office(2000-2003)中,如果未能釋放 Office API 對象,則會導致 Excel 主視窗無限期地掛起。 雖然較新的版本容錯率更高,但 Excel 進程仍然會在任務管理器中累積,導致記憶體洩漏,並可能造成 Excel 電子表格檔案的檔案鎖定問題。

對於伺服器端或計劃應用程式來說,這個問題尤其棘手,因為進程會隨著時間的推移而不斷累積,直到伺服器記憶體耗盡。 了解其發生原因,是選擇合適工具完成工作的第一步。

COM層發生了什麼事?

對 Excel COM 物件進行的任何屬性存取都可能會建立新的 RCW。 當你寫 worksheet.Range["A1"].Value 時,會建立兩個單獨的 COM 物件-一個用於 Range,另一個透過雙點存取隱式建立。 垃圾收集員最終可能會清理這些垃圾,但無法保證何時清理。 在高吞吐量應用中,積壓工作量的成長速度可能超過收集速度。

Windows 內部會統計 COM 參考。 在計數歸零之前,底層進程 (EXCEL.EXE) 會一直運作。呼叫 GC.Collect()GC.WaitForPendingFinalizers() 會強制執行一次垃圾回收,但這種方法會帶來效能損失,並且對於生產程式碼而言並非長久之計。

為什麼雙點圖案會引發問題?

雙點模式 (app.Workbooks.Open(path)) 在 C# 中是慣用的,但在 COM 互通上下文中,它會建立一個未引用的中間物件。 創建了 Workbooks 集合對象,並用它來調用 Open,然後立即使其成為孤立對象,因為你的代碼沒有對該對象的引用。 垃圾回收器沒有可預測的時間表來最終處理這些對象,因此 EXCEL.EXE 會一直保持開啟。

使用 Interop 時唯一安全的方法是將每個中間物件儲存在一個命名變數中,並按照建立的相反順序明確地釋放每個物件。

如何正確釋放 Excel 互通物件?

傳統方法需要對創建的每一個 COM 物件進行細緻的追蹤。 必須避免使用雙點,將每個中間物件儲存在局部變數中,並以相反的順序釋放它們。 以下程式碼示範了 Stack Overflow 答案和 Microsoft 文件中常見的詳細清理模式:

using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

// Verbose Interop cleanup pattern
Excel.Application excelApp = new Excel.Application();
Excel.Workbooks workbooks = excelApp.Workbooks;
Excel.Workbook workbook = workbooks.Open("report.xlsx");
Excel.Sheets sheets = workbook.Sheets;
Excel.Worksheet worksheet = (Excel.Worksheet)sheets[1];

// Work with data
worksheet.Cells[1, 1] = "Updated Value";

// Cleanup -- release EVERY COM object in reverse order
workbook.Close(false);
excelApp.Quit();

Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApp);

GC.Collect();
GC.WaitForPendingFinalizers();
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

// Verbose Interop cleanup pattern
Excel.Application excelApp = new Excel.Application();
Excel.Workbooks workbooks = excelApp.Workbooks;
Excel.Workbook workbook = workbooks.Open("report.xlsx");
Excel.Sheets sheets = workbook.Sheets;
Excel.Worksheet worksheet = (Excel.Worksheet)sheets[1];

// Work with data
worksheet.Cells[1, 1] = "Updated Value";

// Cleanup -- release EVERY COM object in reverse order
workbook.Close(false);
excelApp.Quit();

Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApp);

GC.Collect();
GC.WaitForPendingFinalizers();
$vbLabelText   $csharpLabel

這段程式碼將每個 Excel 物件分別存儲,以確保正確清理。末尾的 GC.Collect()GC.WaitForPendingFinalizers() 呼叫會強制進行垃圾回收。 有些開發者將所有內容都包裹在 try/finally 程式碼區塊中,以確保即使發生異常也能進行清理。

對於標準清理失敗的極端情況,有些團隊會採用使用 Windows 作業物件來終止進程的方法。 這涉及對 SetInformationJobObjectAssignProcessToJobObject 的 P/Invoke 聲明。 雖然這可以作為最後的手段,但這只是治標不治本,並沒有解決根本的設計問題。

如何在 C# 中安裝不依賴 COM 的 Excel 函式庫?

IronXL對 Excel 檔案操作採用了截然不同的方法。 IronXL不封裝 Microsoft Office COM 對象,而是使用自己的解析器和渲染器直接讀取和寫入 Excel 檔案格式。 這意味著沒有 COM 引用,沒有 Office Interop 依賴項,也沒有殘留進程。 你甚至不需要在電腦上安裝微軟Excel。

在 Visual Studio 中透過NuGet套件管理器控制台安裝IronXL :

Install-Package IronXl.Excel
Install-Package IronXl.Excel
SHELL

或使用.NET CLI:

dotnet add package IronXl.Excel
dotnet add package IronXl.Excel
SHELL

安裝完成後,將 using IronXL; 指令新增至您的檔案。現在,您的專案可以直接、原生地存取 Excel 文件操作,而無需任何 Office 相依性。 IronXL 的目標平台為.NET 8、 .NET 9、 .NET 10、 .NET Framework 4.6.2+,可在 Windows、Linux、macOS、Docker 和 Azure 上運作。

需要哪些NuGet套件?

只需要一個NuGet套件:IronXl.Excel。 它不依賴 Microsoft Office、Office Interop 組件或任何 COM 註冊。 這使得部署變得非常簡單——您可以將應用程式發佈為獨立的執行文件,它將在任何未安裝 Office 的伺服器上運行。

對於還需要產生 PDF 的項目, IronPDF與IronXL集成,可以直接將 Excel 資料匯出為 PDF,而無需通過 Excel 自動化流程。

如何在不使用 COM 物件的情況下讀取 Excel 檔案?

以下程式碼示範如何使用IronXL讀取 Excel 檔案。 請注意,無需編寫清理程式碼:

using IronXL;

// Load and read Excel files without COM objects
WorkBook workBook = WorkBook.Load("report.xlsx");
WorkSheet workSheet = workBook.DefaultWorkSheet;

// Access cell values directly
string cellValue = workSheet["A1"].StringValue;
decimal columnSum = workSheet["B2:B10"].Sum();

// 不 cleanup required -- workBook is a standard .NET object
Console.WriteLine($"Cell A1: {cellValue}");
Console.WriteLine($"Sum B2:B10: {columnSum}");
using IronXL;

// Load and read Excel files without COM objects
WorkBook workBook = WorkBook.Load("report.xlsx");
WorkSheet workSheet = workBook.DefaultWorkSheet;

// Access cell values directly
string cellValue = workSheet["A1"].StringValue;
decimal columnSum = workSheet["B2:B10"].Sum();

// 不 cleanup required -- workBook is a standard .NET object
Console.WriteLine($"Cell A1: {cellValue}");
Console.WriteLine($"Sum B2:B10: {columnSum}");
$vbLabelText   $csharpLabel

控制台輸出

釋放 Excel 物件 C#:使用IronXL停止殘留的 Excel 進程:圖 3 - IronXL讀取輸入 Excel 檔案的輸出

IronXL將 Excel 物件作為原生.NET類型處理。當 workBook 變數超出作用域時,標準的.NET垃圾回收機制會自動清理記憶體。無需追蹤 COM 引用、呼叫 Marshal.ReleaseComObject 或強制執行垃圾回收週期。

您也可以在IronXL工作簿中使用 using 區塊進行確定性處置,儘管這不是防止進程洩漏的必要條件—這只是.NET資源管理良好實務的問題。

如何存取多個工作表?

在IronXL中存取多個工作表與操作任何.NET集合一樣直接:

using IronXL;

WorkBook workBook = WorkBook.Load("multi-sheet-report.xlsx");

// Iterate all worksheets
foreach (WorkSheet sheet in workBook.WorkSheets)
{
    string sheetName = sheet.Name;
    int rowCount = sheet.RowCount;
    Console.WriteLine($"Sheet '{sheetName}' has {rowCount} rows");
}

// Access a specific sheet by name
WorkSheet salesSheet = workBook["Sales"];
decimal totalRevenue = salesSheet["C2:C100"].Sum();
Console.WriteLine($"Total Revenue: {totalRevenue:C}");
using IronXL;

WorkBook workBook = WorkBook.Load("multi-sheet-report.xlsx");

// Iterate all worksheets
foreach (WorkSheet sheet in workBook.WorkSheets)
{
    string sheetName = sheet.Name;
    int rowCount = sheet.RowCount;
    Console.WriteLine($"Sheet '{sheetName}' has {rowCount} rows");
}

// Access a specific sheet by name
WorkSheet salesSheet = workBook["Sales"];
decimal totalRevenue = salesSheet["C2:C100"].Sum();
Console.WriteLine($"Total Revenue: {totalRevenue:C}");
$vbLabelText   $csharpLabel

沒有 COM 迭代枚舉器,沒有隱藏的臨時對象,也不需要清理。 IronXL 的 API 完全遵循標準的.NET集合模式。

如何在不使用 Interop 的情況下建立新的 Excel 檔案?

建立 Excel 檔案採用相同的簡單方法。 以下程式碼示範如何建立新工作簿、新增結構化資料、套用基本格式並儲存:

using IronXL;

// Create a new Excel spreadsheet in XLSX format
WorkBook workBook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet workSheet = workBook.CreateWorkSheet("Sales Data");

// Write headers
workSheet["A1"].Value = "Product";
workSheet["B1"].Value = "Units Sold";
workSheet["C1"].Value = "Revenue";

// Write data rows
workSheet["A2"].Value = "Widget Alpha";
workSheet["B2"].Value = 450;
workSheet["C2"].Value = 22500;

workSheet["A3"].Value = "Widget Beta";
workSheet["B3"].Value = 310;
workSheet["C3"].Value = 15500;

// Add a formula
workSheet["C4"].Formula = "=SUM(C2:C3)";

// Save the Excel file
workBook.SaveAs("sales_report.xlsx");
Console.WriteLine("Spreadsheet saved successfully.");
using IronXL;

// Create a new Excel spreadsheet in XLSX format
WorkBook workBook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet workSheet = workBook.CreateWorkSheet("Sales Data");

// Write headers
workSheet["A1"].Value = "Product";
workSheet["B1"].Value = "Units Sold";
workSheet["C1"].Value = "Revenue";

// Write data rows
workSheet["A2"].Value = "Widget Alpha";
workSheet["B2"].Value = 450;
workSheet["C2"].Value = 22500;

workSheet["A3"].Value = "Widget Beta";
workSheet["B3"].Value = 310;
workSheet["C3"].Value = 15500;

// Add a formula
workSheet["C4"].Formula = "=SUM(C2:C3)";

// Save the Excel file
workBook.SaveAs("sales_report.xlsx");
Console.WriteLine("Spreadsheet saved successfully.");
$vbLabelText   $csharpLabel

輸出

釋放 Excel 物件 C#:使用IronXL停止殘留的 Excel 進程:圖 4 - 未透過 Interop 建立的 Excel 檔案

這種方法消除了管理 Excel 應用程式物件、處理未儲存變更提示或確保主執行緒使用 STA 單元模型的複雜性。 IronXL簡化了對電子表格功能的訪問,而無需 Office 加載項依賴或 Interop 組件註冊。

對於需要更複雜操作的場景, IronXL提供了公式計算儲存格樣式設定和多工作表工作簿的方法。 您可以編寫程式碼來操作 Excel 工作表資料、套用格式並匯出為多種文件格式——所有這些都無需擔心 COM 物件生命週期管理。

Excel 互通 和直接函式庫的主要差異是什麼?

下表總結了兩種方法之間最重要的差異:

Excel 互通 與IronXL在 C# 應用程式方面的比較
能力 Excel 互通 IronXL
需要 Microsoft Office 是的
COM物件清理 手冊(每個對象) 自動(.NET GC)
EXCEL.EXE 殘留的風險 高的 沒有任何
適用於伺服器環境 有限(需要STA線程) 是的(所有環境)
Docker/Linux 支持 是的
支援的文件格式 XLS、XLSX(透過 Office) XLS、XLSX、CSV、TSV、JSON
螺紋安全 僅限STA 多執行緒
程式碼複雜度(基本閱讀) 高(多次發布呼叫) 低(3-5 行)

釋放 Excel 物件 C#:使用IronXL停止殘留的 Excel 進程:圖 2 - Interop 與IronXL比較表

IronXL還支援讀取 CSV 檔案將資料匯出到 CSV處理 Excel 圖表以及應用條件格式。 IronXL 的所有功能都無需依賴 Office,因此適用於桌面和伺服器端應用程式。

有關高級場景的更多詳細信息,請參閱IronXL文件IronXL API 參考。 您也可以瀏覽IronXL範例庫,其中包含涵蓋數十種常見 Excel 自動化任務的即用型程式碼範例。

Excel公式和資料驗證方面又該如何操作呢?

IronXL原生支援讀取和寫入 Excel 公式。 您可以設定儲存格的 Formula 屬性, IronXL會將公式儲存在檔案中並對其進行計算。 對於資料驗證規則, IronXL支援下拉清單、數字範圍約束和日期驗證——所有這些都不需要 Excel 執行計算。

該程式庫也支援Excel 密碼保護合併儲存格Excel 凍結窗格配置。 請參閱IronXL教程,以取得每個功能的逐步指導。

如何從 Excel 互通 遷移到原生.NET程式庫?

將現有的基於 Interop 的程式碼庫遷移到IronXL通常涉及四個步驟:

  1. 刪除 Microsoft.Office.Interop.Excel NuGet引用和 COM 註冊
  2. 透過NuGet安裝 IronXl.Excel
  3. 將 Interop 物件建立替換為IronXL等效項(WorkBook.Load, WorkBook.Create)
  4. 刪除所有 Marshal.ReleaseComObject 呼叫和 GC.Collect 模式

大多數屬性名稱的對應都很直觀:worksheet.Cells[row, col] 變成 workSheet[$"{col}{row}"].Value,而 workbook.SaveAs(path) 幾乎保持不變。 IronXL遷移指南涵蓋了常見的轉換模式。

需要關注的一個面向是穿線。 互通需要 STA 線程,這強制要求在ASP.NET中進行特定的線程池配置。 切換到IronXL後,您可以移除任何 [STAThread] 屬性和線程單元設定 -- IronXL預設是線程安全的。

對於跨多個檔案的大規模遷移, IronXL批次處理範例示範如何使用平行循環和非同步模式高效地處理數百個 Excel 檔案。

下一步計劃是什麼?

Excel 互通 中的 COM 物件清理問題多年來一直困擾著.NET開發人員。 追蹤每個中間對象,按正確的順序釋放它們,並在不洩露引用的情況下處理異常,這給原本簡單的電子表格操作增加了很大的複雜性。

IronXL提供了一條更清晰的發展路徑。 它直接操作 Excel 文件格式(獨立於 Microsoft Office),並從來源上消除了 COM 物件問題。 無論您是讀取現有文件、建立新文件或處理大批量數據, IronXL都能以現代.NET開發所需的簡單性處理 Excel 電子表格操作。

開始使用:

下載IronXL免費試用版,並在您自己的專案中進行測試。

  • 請查閱IronXL文件以了解架構和 API 詳情。
  • 瀏覽IronXL範例庫,查看涵蓋讀取、寫入、格式化和公式求值的程式碼範例
  • 有關包括免版稅再分發在內的授權選項,請參閱IronXL定價頁面

若要與.NET生態系中的其他 Excel 庫進行比較,請參閱Microsoft 關於 Excel 互通 的文件EPPlus 庫的GitHub儲存庫ClosedXML 項目,以了解各種選項的權衡取捨。 IronXL 的優勢在於,它將豐富的 API、無需 Office 的部署以及完全的跨平台支援結合在一個商業許可證下。

常見問題解答

IronXL 是什麼?

IronXL 是一套 .NET 程式庫,可簡化 C# 應用程式中 Excel 檔案的操作流程,無需使用 Microsoft Office Interop。

為什麼要在 C# 中釋放 Excel 物件?

在 C# 中釋放 Excel 物件至關重要,以防止 Excel 程序持續運行,這可能導致效能問題和記憶體洩漏。

IronXL 如何協助清理 Excel 物件?

IronXL 可自動執行 Excel 物件清理,從而降低在 C# 中手動管理 Interop 物件所帶來的複雜性與錯誤。

在 C# 中使用 Excel Interop 會面臨哪些挑戰?

在 C# 中進行 Excel 互通時,由於需手動管理 COM 物件,常會導致殘留進程和記憶體洩漏等問題。

若未安裝 Microsoft Office,是否仍可操作 Excel 檔案?

是的,IronXL 讓您無需在系統上安裝 Microsoft Office,即可操作 Excel 檔案。

IronXL 是否支援所有 Excel 檔案格式?

IronXL 支援多種 Excel 檔案格式,包括 XLSX、XLS、CSV 等,可進行多樣化的檔案操作。

IronXL 適合用於大規模的 Excel 檔案操作嗎?

IronXL 旨在高效處理大規模的 Excel 檔案操作,使其適合用於 Enterprise 級應用程式。

使用 IronXL 代替 Excel Interop 有哪些優勢?

相較於 Excel Interop,IronXL 具備簡化程式碼、提升效能,以及消除 COM 相關問題等優勢。

如何將 IronXL 整合到我的 C# 專案中?

您可以透過 NuGet 套件管理員安裝 IronXL,並在應用程式程式碼中引用它,將其整合至您的 C# 專案中。

IronXL 是否支援 Excel 公式?

是的,IronXL 支援 Excel 公式,讓您能在 C# 應用程式中讀取、寫入並評估這些公式。

Jordi Bardia
軟體工程師
Jordi 在 Python、C# 和 C++ 上最得心應手,當他不在 Iron Software 展現技術時,便在做遊戲編程。在分担產品测测试,產品開發和研究的责任時,Jordi 為持续的產品改進增值。他说这种多样化的经验使他受到挑战并保持参与, 而这也是他与 Iron Software 中工作一大乐趣。Jordi 在佛罗里达州迈阿密长大,曾在佛罗里达大学学习计算机科学和统计学。

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me