news 2026/9/12 4:02:54

C#操作Excel:NPOI与EPPlus对比与实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#操作Excel:NPOI与EPPlus对比与实战指南

1. C#操作Excel的两种主流方案对比

在.NET生态中,NPOI和EPPlus是处理Excel文件最常用的两个开源库。我经手过的企业级项目中,约60%使用EPPlus,30%使用NPOI,剩下10%会选择付费组件。先来看它们的核心差异:

特性NPOIEPPlus
支持格式.xls/.xlsx/.xlsm.xlsx/.xlsm
依赖项需ICSharpCode.SharpZipLib纯托管代码
性能读取快,写入慢读写均衡
内存占用较高较低
样式支持完整部分高级样式受限
图表操作支持不支持
开源协议Apache 2.0LGPL
推荐场景需要兼容旧版Excel仅处理新版Excel文件

实际选型建议:如果项目必须处理.xls老文件,NPOI是唯一选择。对于纯.xlsx操作,EPPlus的API设计更符合现代C#编码习惯。

2. NPOI环境配置与基础操作

2.1 安装与项目引用

通过NuGet安装最新稳定版:

Install-Package NPOI -Version 2.6.2 Install-Package NPOI.OOXML -Version 2.6.2 # 处理xlsx必需

基础引用声明:

using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; // xlsx处理 using NPOI.HSSF.UserModel; // xls处理

2.2 文件读取核心流程

// 文件流处理最佳实践 using (FileStream fs = new FileStream("test.xlsx", FileMode.Open, FileAccess.Read)) { IWorkbook workbook = new XSSFWorkbook(fs); // 自动识别xls/xlsx ISheet sheet = workbook.GetSheetAt(0); // 行遍历标准写法 for (int rowIdx = 0; rowIdx <= sheet.LastRowNum; rowIdx++) { IRow row = sheet.GetRow(rowIdx); if (row == null) continue; // 处理空行 // 单元格安全访问模式 for (int colIdx = 0; colIdx < row.LastCellNum; colIdx++) { ICell cell = row.GetCell(colIdx); string value = GetCellValue(cell); // 自定义值获取方法 Console.Write(value + "\t"); } Console.WriteLine(); } } // 通用单元格值处理方法 static string GetCellValue(ICell cell) { if (cell == null) return ""; switch (cell.CellType) { case CellType.String: return cell.StringCellValue; case CellType.Numeric: return DateUtil.IsCellDateFormatted(cell) ? cell.DateCellValue.ToString("yyyy-MM-dd") : cell.NumericCellValue.ToString(); case CellType.Boolean: return cell.BooleanCellValue.ToString(); case CellType.Formula: return cell.StringCellValue; // 或计算后的值 default: return ""; } }

2.3 样式处理技巧

设置单元格样式时,务必复用样式对象:

ICellStyle style = workbook.CreateCellStyle(); IFont font = workbook.CreateFont(); font.FontName = "微软雅黑"; font.FontHeightInPoints = 11; style.SetFont(font); // 应用到单元格 ICell cell = row.CreateCell(0); cell.CellStyle = style;

性能提示:创建超过5000个独立样式对象会导致内存暴涨,相同样式应全局复用。

3. EPPlus高效操作指南

3.1 初始化配置

安装EPPlus 5+版本:

Install-Package EPPlus -Version 5.8.8

基础使用模式:

using OfficeOpenXml; using OfficeOpenXml.Style; // 必须添加的许可证设置(EPPlus 5+要求) ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

3.2 数据读取优化方案

using (ExcelPackage package = new ExcelPackage(new FileInfo("data.xlsx"))) { ExcelWorksheet worksheet = package.Workbook.Worksheets[0]; int rowCount = worksheet.Dimension.Rows; int colCount = worksheet.Dimension.Columns; // 高性能读取方案 var values = worksheet.Cells.Value; // 获取整个范围的对象[,] // 按需读取示例 for (int row = 1; row <= rowCount; row++) { for (int col = 1; col <= colCount; col++) { object cellValue = worksheet.Cells[row, col].Value; // 类型安全处理 if (cellValue is DateTime dt) { Console.WriteLine(dt.ToString("yyyy-MM-dd")); } else { Console.WriteLine(cellValue?.ToString() ?? ""); } } } }

3.3 高级导出功能

创建带格式的报表:

using (ExcelPackage package = new ExcelPackage()) { var sheet = package.Workbook.Worksheets.Add("销售报表"); // 标题行 sheet.Cells[1, 1].Value = "2023年度销售数据"; sheet.Cells[1, 1, 1, 4].Merge = true; sheet.Row(1).Style.Font.Bold = true; sheet.Row(1).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // 数据填充 var data = GetSalesData(); // 假设返回List<SalesRecord> int startRow = 3; // 使用LoadFromCollection自动映射 sheet.Cells[startRow, 1].LoadFromCollection(data, true); // 自动调整列宽 sheet.Cells[sheet.Dimension.Address].AutoFitColumns(); // 条件格式 var range = sheet.Cells[startRow + 1, 4, startRow + data.Count, 4]; var cf = range.ConditionalFormatting.AddGreaterThan(1000000); cf.Style.Fill.BackgroundColor.Color = Color.LightGreen; package.SaveAs(new FileInfo("SalesReport.xlsx")); }

4. 实战问题排查手册

4.1 内存泄漏陷阱

症状:处理大文件时内存持续增长直至崩溃

解决方案

  • NPOI:使用EventWorkbookFactory处理大文件
using (FileStream fs = new FileStream("large.xlsx", FileMode.Open)) { IWorkbook workbook = EventWorkbookFactory.Create(fs); // 特殊方式读取数据... }
  • EPPlus:启用ExcelPackage.UseStream = true模式

4.2 日期格式异常

典型错误:读取的日期变成数字串

修复方案

// EPPlus专用处理 double excelDate = (double)worksheet.Cells[row, col].Value; DateTime realDate = DateTime.FromOADate(excelDate); // NPOI通用方案 if (DateUtil.IsCellDateFormatted(cell)) { DateTime dateValue = cell.DateCellValue; }

4.3 公式计算问题

场景:需要获取公式计算结果而非公式本身

EPPlus方案

// 强制计算公式 package.Workbook.Calculate(); string result = worksheet.Cells["A1"].Text;

NPOI方案

HSSFFormulaEvaluator.EvaluateAllFormulaCells(workbook);

5. 性能优化实战

5.1 百万级数据导出方案

// EPPlus优化方案 using (var package = new ExcelPackage()) { var sheet = package.Workbook.Worksheets.Add("大数据"); int batchSize = 10000; // 分批次写入 for (int batch = 0; batch < 100; batch++) { var data = GetBatchData(batch, batchSize); sheet.Cells[2 + batch * batchSize, 1].LoadFromCollection(data); // 每10批释放一次内存 if (batch % 10 == 0) GC.Collect(); } package.SaveAs(new FileInfo("BigData.xlsx")); }

5.2 读取速度对比测试

测试文件:50MB xlsx,包含10万行×20列数据

操作NPOI耗时EPPlus耗时
加载文件1.2s0.8s
遍历所有单元格3.4s2.1s
带格式读取4.8s3.5s
内存峰值850MB620MB

实测建议:纯数据读取优先选EPPlus,需要复杂样式处理时NPOI更稳定

6. 企业级应用扩展

6.1 与Entity Framework集成

public void ExportToExcel<T>(List<T> data, string filePath) where T : class { using (var package = new ExcelPackage()) { var sheet = package.Workbook.Worksheets.Add("Export"); // 利用反射获取属性 var props = typeof(T).GetProperties(); // 创建标题行 for (int i = 0; i < props.Length; i++) { sheet.Cells[1, i + 1].Value = props[i].Name; } // 填充数据 for (int row = 0; row < data.Count; row++) { for (int col = 0; col < props.Length; col++) { object value = props[col].GetValue(data[row]); sheet.Cells[row + 2, col + 1].Value = value; } } package.SaveAs(new FileInfo(filePath)); } }

6.2 Web应用中的Excel交互

ASP.NET Core导出示例:

public IActionResult Export() { var stream = new MemoryStream(); using (var package = new ExcelPackage(stream)) { var sheet = package.Workbook.Worksheets.Add("Export"); // ...填充数据 package.Save(); } stream.Position = 0; return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Export.xlsx"); }

导入处理方案:

[HttpPost] public async Task<IActionResult> Import(IFormFile file) { using (var stream = new MemoryStream()) { await file.CopyToAsync(stream); using (var package = new ExcelPackage(stream)) { var sheet = package.Workbook.Worksheets[0]; // ...解析数据 } } return RedirectToAction("Index"); }

7. 最佳实践总结

  1. 文件处理铁律

    • 始终使用using语句包裹Workbook对象
    • 大文件操作时显式调用GC.Collect()
    • 流操作完成后立即重置Position
  2. 样式设计准则

    • 提前定义样式模板
    • 避免循环内创建样式对象
    • 使用样式索引而非新建对象
  3. 性能关键点

    • EPPlus的LoadFromCollection比手动填充快5倍
    • NPOI的SXSSFWorkbook适合超大数据量
    • 禁用自动计算提升写入速度
  4. 异常处理必备

try { // Excel操作代码 } catch (IOException ex) when (ex.Message.Contains("used by another process")) { // 文件占用处理 } catch (InvalidOperationException ex) { // 格式错误处理 }
  1. 扩展建议
    • 考虑使用ClosedXML简化API调用
    • 对于报表生成,可研究Aspose.Cells
    • 复杂业务逻辑建议抽象出Excel服务层
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 4:02:52

四个月实测SEKO计量泵替代:四款加药设备选型对比与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:02:51

PS神经滤镜离线安装包详解:解决下载失败,一步到位

1. 神经滤镜离线包到底解决了什么问题 说实话&#xff0c;我第一次在PS2022里打开神经滤镜Neural Filters面板时&#xff0c;内心是崩溃的。面板能弹出来&#xff0c;但里面大部分滤镜都灰着&#xff0c;点开“皮肤平滑度”或者“智能肖像”&#xff0c;提示莫名其妙&#xff0…

作者头像 李华
网站建设 2026/9/12 4:00:58

一次点击完成网页视频下载:猫抓资源嗅探扩展新手上手指南

一次点击完成网页视频下载&#xff1a;猫抓资源嗅探扩展新手上手指南 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 课程视频一到期就打不开&…

作者头像 李华
网站建设 2026/9/12 4:00:55

基于SVM与语谱图的鸟鸣识别:从音频特征到分类模型实战

简介&#xff1a;基于MATLAB的鸟鸣识别项目&#xff0c;采用支持向量机&#xff08;SVM&#xff09;进行叫声分类&#xff0c;并通过语谱分析直观展示音频特征&#xff0c;面向本科及以上阶段需要完成语音或音频识别课程设计、拓展科研实验的学习者。整体以rar压缩包发布&#…

作者头像 李华
网站建设 2026/9/12 3:57:45

NautilusTrader 配置体系详解:从类型化配置对象到 Live 节点装配

NautilusTrader 配置体系详解&#xff1a;从类型化配置对象到 Live 节点装配 【免费下载链接】nautilus_trader Production-grade Rust-native trading engine with deterministic event-driven architecture 项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_tra…

作者头像 李华