npoi 不支持 word 文件(.docx/.doc),仅支持 excel、powerpoint 和 visio;操作 word 应选用 interop.word(需本地 office)或 spire.doc 等纯托管库。

NPOI 不支持 Word 文件(.docx / .doc)。它只处理 Excel(.xls / .xlsx)、PowerPoint(.pptx)和 Visio(.vsdx)——Word 不在它的能力范围内。
如果你看到“NPOI 操作 Word”的说法,基本是混淆了库,或是误用了旧资料。真正能操作 Word 的主流 .NET 方案只有两类:
- Microsoft.Office.Interop.Word(需本机装 Office)
- 第三方纯托管库(如 Spire.Doc、DocX、GemBox.Document)
下面直奔实操重点:
为什么 NPOI 不能读写 Word
NPOI 的设计目标明确聚焦于 Office Open XML 中的 SpreadsheetML(Excel)和 PresentationML(PPT),而 WordprocessingML(Word)结构更复杂,涉及段落、样式、节、域、书签、页眉页脚等大量上下文依赖对象。Npoi 源码中完全不存在 WordDocument、Paragraph 或 Run 类;所有命名空间都止步于 NPOI.XWPF —— 但注意:这个命名空间是空的,从未实现。NuGet 上任何标称 “NPOI for Word” 的包,要么是仿冒,要么是包装了其他库的壳。
Interop.Word 写入 Word 的关键避坑点
用 Microsoft.Office.Interop.Word 创建或修改 Word 文档时,最容易卡死、报错或残留 winword.exe 进程:
-
Application对象必须显式调用Quit(),且推荐在finally块中执行,否则后台进程常驻 - 不要直接用
doc.Content.Text = "xxx"赋值 —— 这会清空全部格式,应改用Range插入:range.Collapse(WdCollapseDirection.wdCollapseEnd); range.Text = "new text"; - 保存路径必须含完整文件名和扩展名,例如
"C:\report.docx";只给目录会抛COMException - 若目标机器没装 Microsoft Office(比如服务器环境),interop 将直接失败 —— 它不是纯托管库,强依赖 Office COM 组件
替代方案:用 Spire.Doc 实现无 Office 依赖的 Word 操作
Spire.Doc 是目前最稳定的纯 .NET Word 库,支持 .NET Framework 和 .NET Core/.NET 5+,无需 Office 安装:
生产级WordPress REST API集成,用于管理文章、页面、媒体、WooCommerce产品、Elementor内容、SEO元数据、ACF及JetEngine字段
- 安装:
Install-Package Spire.Doc - 创建新文档:
Document doc = new Document(); Section section = doc.AddSection(); Paragraph para = section.AddParagraph(); para.AppendText("Hello, World!"); doc.SaveToFile("out.docx", FileFormat.Docx); - 追加内容到末尾:获取最后一段的
Paragraph,再调用AddParagraph(),或直接用section.Body.Paragraphs.Insert() - 查找替换:用
doc.Replace("old", "new", false, true),第三个参数是是否忽略大小写,第四个是是否全词匹配
注意:免费版有页数限制(最多 10 页)和水印,商用需授权。
Interop 和 Spire.Doc 的选择逻辑
选 Microsoft.Office.Interop.Word 当且仅当你:需要精确复现用户端 Word 的渲染效果(比如带宏、复杂域代码、OLE 对象)、开发桌面工具且目标机器必装 Office、或维护老项目无法更换依赖。
选 Spire.Doc(或 GemBox.Document)当你要:部署到服务器、做批量生成/合并/提取、避免 COM 交互不稳定、或需要跨平台(.NET 6+ Linux 支持有限但可用)。
真正容易被忽略的是:**Interop 的线程模型(STA)要求**。如果在 ASP.NET 或后台线程里调用,不设 [STAThread] 或未正确设置线程 ApartmentState,第一次调用就会 hang 住 —— 这个错误不会立刻报异常,而是静默卡死。










