C#如何使用NPOI按照模板生成Word文档

来源:个人站长网作者:小白龙头衔:草根站长
导读:本期聚焦于小伙伴创作的《C#如何使用NPOI按照模板生成Word文档》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何使用NPOI按照模板生成Word文档》有用,将其分享出去将是对创作者最好的鼓励。

在C#项目开发中,按照固定模板生成Word文档是常见需求,比如批量生成员工合同、项目报告、录取通知书等文件,使用NPOI库可以在无Office依赖的环境下高效完成这个任务。

C#如何使用NPOI按照模板生成Word文档

环境准备

首先需要安装NPOI相关的NuGet包,在Visual Studio的包管理器控制台执行以下命令即可完成安装:

Install-Package NPOI
Install-Package NPOI.OOXML

这两个包分别提供了基础的NPOI功能和Office Open XML格式文档的支持,Word的.docx格式属于OOXML格式,因此需要同时安装这两个包。

制作Word模板

首先需要制作一个Word模板文件,在模板中需要替换的位置使用占位符标记,比如使用${占位符名称}的格式,例如:

  • 员工姓名:${EmployeeName}
  • 入职日期:${EntryDate}
  • 岗位名称:${Position}

模板制作完成后,将文件保存为.docx格式,放到项目的指定目录下,比如设置为始终复制到输出目录。

核心实现代码

下面是完整的按照模板生成Word文档的C#代码实现:

using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;

namespace WordTemplateGenerator
{
    public class WordGenerator
    {
        /// <summary>
        /// 按照模板生成Word文档
        /// </summary>
        /// <param name="templatePath">模板文件路径</param>
        /// <param name="outputPath">输出文件路径</param>
        /// <param name="replaceData">替换数据字典,key为占位符名称,value为替换内容</param>
        public static void GenerateWordByTemplate(string templatePath, string outputPath, Dictionary<string, string> replaceData)
        {
            // 读取模板文件
            using (FileStream templateStream = new FileStream(templatePath, FileMode.Open, FileAccess.Read))
            {
                XWPFDocument doc = new XWPFDocument(templateStream);
                
                // 替换段落中的占位符
                foreach (XWPFParagraph paragraph in doc.Paragraphs)
                {
                    ReplaceParagraphText(paragraph, replaceData);
                }
                
                // 替换表格中的占位符
                foreach (XWPFTable table in doc.Tables)
                {
                    foreach (XWPFTableRow row in table.Rows)
                    {
                        foreach (XWPFTableCell cell in row.GetTableCells())
                        {
                            foreach (XWPFParagraph cellParagraph in cell.Paragraphs)
                            {
                                ReplaceParagraphText(cellParagraph, replaceData);
                            }
                        }
                    }
                }
                
                // 保存生成的文档
                using (FileStream outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
                {
                    doc.Write(outputStream);
                }
            }
        }
        
        /// <summary>
        /// 替换段落中的占位符
        /// </summary>
        private static void ReplaceParagraphText(XWPFParagraph paragraph, Dictionary<string, string> replaceData)
        {
            // 获取段落的所有文本片段
            List<XWPFRun> runs = new List<XWPFRun>(paragraph.Runs);
            if (runs.Count == 0) return;
            
            // 拼接所有run的文本,得到完整段落文本
            string fullText = string.Join("", runs.ConvertAll(run => run.Text ?? ""));
            
            // 检查是否有需要替换的占位符
            bool hasReplace = false;
            foreach (var item in replaceData)
            {
                string placeholder = "${" + item.Key + "}";
                if (fullText.Contains(placeholder))
                {
                    fullText = fullText.Replace(placeholder, item.Value);
                    hasReplace = true;
                }
            }
            
            // 如果有替换,清空原有run,重新设置文本
            if (hasReplace)
            {
                for (int i = runs.Count - 1; i >= 0; i--)
                {
                    paragraph.RemoveRun(i);
                }
                XWPFRun newRun = paragraph.CreateRun();
                newRun.SetText(fullText);
                // 可以复制原有第一个run的样式
                if (runs.Count > 0)
                {
                    newRun.FontFamily = runs[0].FontFamily;
                    newRun.FontSize = runs[0].FontSize;
                    newRun.IsBold = runs[0].IsBold;
                    newRun.IsItalic = runs[0].IsItalic;
                }
            }
        }
    }
}

调用示例

下面是调用上述方法的示例代码:

using System;
using System.Collections.Generic;

namespace WordTemplateGenerator
{
    class Program
    {
        static void Main(string[] args)
        {
            // 模板路径和输出路径
            string templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Template", "EmployeeContract.docx");
            string outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Output", "张三_劳动合同.docx");
            
            // 准备替换数据
            Dictionary<string, string> replaceData = new Dictionary<string, string>
            {
                { "EmployeeName", "张三" },
                { "EntryDate", "2024-05-20" },
                { "Position", "高级开发工程师" },
                { "Salary", "25000" }
            };
            
            try
            {
                // 生成文档
                WordGenerator.GenerateWordByTemplate(templatePath, outputPath, replaceData);
                Console.WriteLine("Word文档生成成功,路径:" + outputPath);
            }
            catch (Exception ex)
            {
                Console.WriteLine("生成文档失败:" + ex.Message);
            }
        }
    }
}

注意事项

  • 模板中的占位符不要拆分到多个XWPFRun中,否则会导致替换失败,建议占位符作为完整的文本片段存在。
  • 如果需要替换图片,需要额外处理图片的替换逻辑,上述代码仅支持文本占位符的替换。
  • 生成的文档路径需要确保目录存在,否则会抛出文件不存在的异常,可以在生成前判断目录是否存在,不存在则创建。
  • 如果需要处理复杂的格式,比如保留原有占位符的样式,需要更精细地处理XWPFRun的样式复制逻辑。

C#NPOIWord模板Word生成修改时间:2026-07-08 08:06:27

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。