Microsoft.Office.Interop.Word (NuGet: Microsoft.Office.Interop.Word 或 COM 參考)。using System;
using System.IO;
using System.Reflection;
using Microsoft.Office.Interop.Word;
public class WordProcessor : IDisposable
{
private Application _app;
private Document _doc;
private bool _disposed;
public WordProcessor(bool visible = false)
{
_app = new Application { Visible = visible };
// 關閉自動更新欄位、自動儲存提示等干擾
_app.DisplayAlerts = WdAlertLevel.wdAlertsNone;
_app.Options.SaveNormalTemplate = false;
}
///
/// 開啟範本檔,另存為新檔並處理書籤
///
public void ProcessTemplate(string templatePath, string outputPath, Dictionary bookmarks)
{
if (!File.Exists(templatePath))
throw new FileNotFoundException("範本檔不存在", templatePath);
object missing = Missing.Value;
object fileName = templatePath;
object readOnly = false;
object isVisible = false;
_doc = _app.Documents.Open(ref fileName, ref missing, ref readOnly, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref isVisible, ref missing, ref missing, ref missing, ref missing);
// 另存為新檔 (保留原範本)
object newFileName = outputPath;
_doc.SaveAs2(ref newFileName, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
// 替換書籤內容
foreach (var kvp in bookmarks)
{
if (_doc.Bookmarks.Exists(kvp.Key))
{
Range range = _doc.Bookmarks[kvp.Key].Range;
range.Text = kvp.Value;
// 重新建立書籤以便後續再次替換
_doc.Bookmarks.Add(kvp.Key, range);
}
}
_doc.Save();
}
///
/// 直接開啟現有檔案處理 (不另存)
///
public void ProcessExisting(string filePath, Dictionary bookmarks)
{
object missing = Missing.Value;
object fileName = filePath;
_doc = _app.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
foreach (var kvp in bookmarks)
{
if (_doc.Bookmarks.Exists(kvp.Key))
{
Range range = _doc.Bookmarks[kvp.Key].Range;
range.Text = kvp.Value;
_doc.Bookmarks.Add(kvp.Key, range);
}
}
_doc.Save();
}
public void Dispose()
{
if (_disposed) return;
try
{
_doc?.Close(WdSaveOptions.wdDoNotSaveChanges);
_app?.Quit();
}
catch { /* 忽略關閉錯誤 */ }
finally
{
// 釋放 COM 物件
if (_doc != null) Marshal.ReleaseComObject(_doc);
if (_app != null) Marshal.ReleaseComObject(_app);
_doc = null;
_app = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
_disposed = true;
}
}
var bookmarks = new Dictionary
{
{ "ClientName", "王小明" },
{ "Date", DateTime.Today.ToString("yyyy年MM月dd日") },
{ "Amount", "NT$ 1,234,567" },
{ "Address", "台北市信義區信義路五段7號" }
};
using (var wp = new WordProcessor(visible: false))
{
wp.ProcessTemplate(@"C:\Templates\Contract.docx", @"C:\Output\Contract_王小明.docx", bookmarks);
}
Console.WriteLine("文件產生完成");
| 項目 | 說明 |
|---|---|
| 書籤替換 | 必須先取得 Range,設定 Text,再 Bookmarks.Add 重建書籤,否則書籤會被覆寫消失。 |
| 儲存方法 | SaveAs2 (Word 2010+) 支援更多格式參數;SaveAs 為舊版相容。 |
| 隱藏 Word 視窗 | 建構子 Visible = false,生產環境必須隱藏,否則會彈出視窗干擾。 |
| 記憶體洩漏 | 務必 Marshal.ReleaseComObject 釋放 RCW,並呼叫 GC.Collect 強制清理。 |
| 例外處理 | COM 例外為 COMException,錯誤碼 0x800Axxxx 可查 MSDN 對照。 |
// NuGet: DocumentFormat.OpenXml
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using (var doc = WordprocessingDocument.Open(@"C:\Output\Contract.docx", true))
{
var body = doc.MainDocumentPart.Document.Body;
// 文字替換、表格操作、樣式設定... 純 XML 操作,效能極佳、無相依性
}
建議: 伺服器端批次產生文件請優先使用 Open XML SDK;僅需客戶端互動、列印、宏執行才用 Interop。
原文連結:https://www.bianceng.cn/Programming/csharp/201410/45580.htm