NPOI填充Excel模板最稳,三步完成:读模板→找占位符→写值;需注意空行导致NullReferenceException、单元格类型设置、样式手动复制、公式需手动计算、流必须正确释放,且不支持下拉列表等高级功能。

用 NPOI 填充 Excel 模板最稳,别碰 Microsoft.Office.Interop.Excel
Interop 依赖本地 Office 安装、多线程崩溃、服务器上根本跑不起来——这是生产环境踩过最多坑的点。NPOI 是纯 .NET 实现,读写 .xlsx 和 .xls 都支持,模板填充只要三步:读模板 → 找占位符 → 写值。它不渲染样式,但能保留模板里所有格式、公式、合并单元格。
常见错误现象:NullReferenceException 在 sheet.GetRow(...).GetCell(...),因为模板里某行/列压根没被 Excel “初始化”(比如空行 Excel 不存,GetRow 返回 null);还有人直接改 cell.StringCellValue 却忘了设 cell.CellType = CellType.String,导致写进去是乱码或报错。
- 模板里用
{{Name}}、${Age}这类简单占位符,别用复杂表达式——NPOI 不解析逻辑,只做字符串替换 - 如果模板有公式(如
=SUM(A2:A10)),填充后要调用workbook.GetCreationHelper().CreateFormulaEvaluator().EvaluateAll()才能刷新结果 - 日期、数字类型填入时,必须用
cell.SetCellValue(DateTime.Now)或cell.SetCellValue(123.45),不能塞字符串,否则 Excel 会当文本处理,排序/求和全失效
Sheet.CopyRow 不是标准 API,复制多行得自己遍历
NPOI 没有内置的“复制一行带样式”方法,网上很多教程抄来抄去的 CopyRow 是别人封装的扩展方法,不是原生功能。想根据模板生成 N 行数据(比如订单明细),不能幻想“复制模板行一次搞定”,必须手动处理每行的单元格类型、样式、边框、字体。
使用场景:模板中有一行“明细”作为样例,后面要追加 50 条记录。这时候容易踩的坑是只复制了值,没复制 CellStyle,结果新行全是默认字体、无边框、日期变数字。
- 先用
sheet.GetRow(5)拿到模板行,再用workbook.CreateCellStyle()复制其样式(注意:CloneStyleFrom只复制样式属性,不复制字体对象,字体得单独workbook.CloneFont) - 对每一列,检查原单元格的
CellType,再调用对应SetCellValue方法(SetCellValue(string)/SetCellValue(double)/SetCellValue(DateTime)) - 合并单元格(
sheet.AddMergedRegion(new CellRangeAddress(...)))要重新加,不会随行复制
填充后文件打不开?大概率是 FileStream 没关或 workbook.Write 被调两次
导出 Excel 文件后双击提示“文件损坏”,90% 是流没正确释放或写操作冲突。典型错误:用 using (var fs = new FileStream(...)) 打开文件,但在 workbook.Write(fs) 后没确保 fs 关闭;或者在 ASP.NET Core 中返回 FileResult 时,既调了 workbook.Write(stream),又让框架自动 flush 流,造成重复写。
性能影响:大模板(万行+)反复 GetRow/GetCell 查找很慢,别在循环里反复用 sheet.GetRow(i).GetCell(j),先缓存行和单元格引用。
- 写文件务必用
using (var fs = new FileStream(path, FileMode.Create)) { workbook.Write(fs); },确保流关闭 - Web 场景下,用
MemoryStream构造 workbook,再用Controller.File(ms.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "report.xlsx") - 不要对同一个
Workbook实例并发写入——NPOI 不是线程安全的,多用户导出需每次新建实例
模板里的下拉列表、条件格式、图表全丢了?对,NPOI 确实不支持
NPOI 能读写单元格值、字体、边框、背景色、合并区域,但高级功能如数据验证(下拉)、条件格式、图表、批注、VBA 宏,统统不支持。如果你的模板靠下拉选“部门”来联动其他列,或者用红绿底色标异常值,填充完这些都会消失。
这不是 bug,是设计限制。官方 issue 里明确说“数据验证太复杂,暂不计划支持”。所以真要用这些功能,要么换工具(如 EPPlus,但注意它 6.x 起商用要授权),要么接受模板降级——把下拉改成普通文本说明,条件格式用颜色代码替代(比如“状态=异常”就手动设红色字体)。
容易被忽略的地方:Excel 模板里隐藏的列、筛选器、分页符、打印区域,NPOI 也不会保留。如果业务强依赖这些,得在填充后用 PowerShell 或 Excel COM(仅限桌面环境)补一遍——但这已经超出“模板填充”的范畴了。


















