將 DataTable 導出 Excel 是企業級應用的高頻需求。本文提供基於 Microsoft.Office.Interop.Excel (COM) 的經典方案,並分析其優缺點,推薦現代無依賴的開源庫替代方案。
適用於服務器/客戶端均安裝 Office 且對格式控制要求極高 (如合併儲存格、樣式、圖表) 的場景。
using System;
using System.Data;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
public class ExcelExporterCom
{
public void ExportToExcel(DataTable dtSource, string filePath)
{
if (dtSource == null || dtSource.Rows.Count == 0) return;
Excel.Application xlApp = null;
Excel.Workbook xlBook = null;
Excel.Worksheet xlSheet = null;
try
{
xlApp = new Excel.Application();
xlApp.DisplayAlerts = false; // 關閉覆蓋提示
xlApp.ScreenUpdating = false; // 關閉屏幕刷新,提速
xlBook = xlApp.Workbooks.Add(Type.Missing);
xlSheet = (Excel.Worksheet)xlBook.ActiveSheet;
xlSheet.Name = "數據導出";
// 1. 寫入表頭
for (int col = 0; col < dtSource.Columns.Count; col++)
{
xlSheet.Cells[1, col + 1] = dtSource.Columns[col].ColumnName;
// 可選:設置表頭樣式
// ((Excel.Range)xlSheet.Cells[1, col + 1]).Font.Bold = true;
}
// 2. 批量寫入數據 (陣列賦值比逐單元格快 100 倍以上)
object[,] dataArray = new object[dtSource.Rows.Count, dtSource.Columns.Count];
for (int row = 0; row < dtSource.Rows.Count; row++)
{
for (int col = 0; col < dtSource.Columns.Count; col++)
{
dataArray[row, col] = dtSource.Rows[row][col];
}
}
// 定義目標範圍並一次性賦值
Excel.Range targetRange = xlSheet.Range[
xlSheet.Cells[2, 1],
xlSheet.Cells[dtSource.Rows.Count + 1, dtSource.Columns.Count]
];
targetRange.Value2 = dataArray;
// 3. 自動調整列寬
targetRange.EntireColumn.AutoFit();
// 4. 保存
xlBook.SaveAs(filePath, Excel.XlFileFormat.xlWorkbookDefault);
}
catch (Exception ex)
{
throw new Exception($"Excel 導出失敗: {ex.Message}", ex);
}
finally
{
// 關鍵:正確釋放 COM 對象,避免 Excel 進程殘留
ReleaseComObject(xlSheet);
ReleaseComObject(xlBook);
if (xlApp != null)
{
xlApp.Quit();
ReleaseComObject(xlApp);
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
private void ReleaseComObject(object obj)
{
if (obj != null && System.Runtime.InteropServices.Marshal.IsComObject(obj))
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}
}
}
private void btnExport_Click(object sender, EventArgs e)
{
using (SaveFileDialog sfd = new SaveFileDialog
{
Filter = "Excel 文件 (*.xlsx)|*.xlsx|Excel 97-2003 (*.xls)|*.xls",
DefaultExt = "xlsx"
})
{
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
new ExcelExporterCom().ExportToExcel(dtFindCharge, sfd.FileName);
MessageBox.Show("導出成功!");
}
catch (Exception ex)
{
MessageBox.Show($"導出失敗: {ex.Message}");
}
}
}
}
EXCEL.EXE 進程,需定時清理。無需安裝 Office,純托管代碼,高性能,支援 .NET Core / .NET 5+ / Linux 容器部署。
| 庫 | 特點 | 適用場景 |
|---|---|---|
| EPPlus (v5+ 商業授權) | 功能最全,支援樣式、圖表、樞紐分析表、數據驗證 | 複雜報表、商業項目 |
| NPOI | Apache POI 移植,支援 .xls/.xlsx,免費開源 | 通用導出、舊版 .xls 支援 |
| ClosedXML | API 簡潔優雅,基於 OpenXML SDK,免費 | 現代 .NET 項目、簡潔代碼風格 |
| MiniExcel | 輕量、流式讀寫、低內存、高性能 | 大數據量導出 (百萬行)、WebAPI 導出 |
// NuGet: Install-Package MiniExcel
using MiniExcelLibs;
using System.Data;
public void ExportWithMiniExcel(DataTable dt, string path)
{
// 一行代碼完成導出,自動處理類型、流式寫入,內存佔用極低
MiniExcel.SaveAs(path, dt, sheetName: "數據導出");
// 進階:自定義列類型、樣式
// var config = new MiniExcelLibs.OpenXml.Configuration() { ... };
// MiniExcel.SaveAs(path, dt, configuration: config);
}
// NuGet: Install-Package ClosedXML
using ClosedXML.Excel;
public void ExportWithClosedXML(DataTable dt, string path)
{
using (var workbook = new XLWorkbook())
{
// DataTable 直接轉 Worksheet,自動處理表頭、類型
var worksheet = workbook.Worksheets.Add(dt, "數據導出");
worksheet.Columns().AdjustToContents(); // 自動列寬
workbook.SaveAs(path);
}
}