epplus 6.2+ 需 .net 6+ 且必须设置 licensecontext,非商用设 noncommercial,商用须授权;读取用 filestream 而非 readallbytes,单元格取值用 value?.tostring(),save() 失败多因路径、文件占用或对象已释放。

EPPlus 不是“拿来就能用”的 Excel 库,尤其在 .NET 6+ 和商用场景下,稍不注意就会在 Save()、Cells[row, col].Value 或许可证校验上卡住。直接说结论:**如果你刚上手,优先用 EPPlus 6.2+ + .NET 6 环境 + 非商业用途,否则立刻掉坑**。
EPPlus 6.x 要求 .NET 6 且必须设 LicenseContext
EPPlus 5.x 只支持 .NET Framework,6.x 起强制要求 .NET 6 或更高版本。不设许可证会直接抛 InvalidOperationException: "Set the LicenseContext" —— 这不是警告,是运行时崩溃。
- 非商业项目:开头加
ExcelPackage.LicenseContext = LicenseContext.NonCommercial; - 商用项目:必须购买授权,或改用
NPOI(Apache 2.0,无限制) - 别在
using块里设 LicenseContext —— 它是静态全局设置,一次即可
读取 Excel 必须用 FileStream,不能用 File.ReadAllBytes()
用 File.ReadAllBytes() 加载再构造 ExcelPackage,大文件(>50MB)极易触发 OutOfMemoryException;更隐蔽的问题是:损坏文件或非 Excel 文件(如 .txt 重命名为 .xlsx)会抛出模糊的 InvalidDataException,而不是明确提示“不是 Excel 格式”。
- 正确做法:先检查扩展名或 MIME 类型,再用
new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read) - 务必在读取前访问
package.Workbook.Worksheets.Count,否则首次访问Worksheets[1]可能因延迟加载失败而报NullReferenceException - 单元格取值统一用
cell.Value?.ToString(),别用cell.Text—— 后者依赖格式字符串,空单元格、数字、日期都可能返回空
写入 Excel 时 Save() 失败的三个高频原因
Save() 报错不报具体路径问题,常让新手反复检查代码逻辑。其实 80% 是环境/权限/状态问题。
- 目标路径父目录不存在 → 抛
DirectoryNotFoundException:用Directory.CreateDirectory(Path.GetDirectoryName(filePath))预创建 - 文件正被 Excel 进程占用 → 抛
IOException:打开时加FileShare.ReadWrite,或确保没人在看这个文件 - 对已 dispose 的
ExcelPackage对象调用Save()→ 抛ObjectDisposedException:确认using块没提前退出,或没在异步中误用同一实例
Worksheet 索引从 1 开始,且空行不会自动跳过
EPPlus 的 Worksheets[0] 是非法操作,会直接 IndexOutOfRangeException;另外它不会帮你过滤空行/空列,worksheet.Dimension.Rows 返回的是 Excel 认为的“已使用区域”,但中间有空行时,这个值可能远大于实际数据行数。
- 安全读取循环:用
for (int row = 1; row ,再判断 <code>worksheet.Cells[row, 1].Value != null - 写入日期别传字符串:
worksheet.Cells[1, 1].Value = DateTime.Now;,不是"2026-04-07" - 设置列宽必须在
Save()前完成,且要写成worksheet.Column(1).Width = 15;,不是worksheet.Cells[1, 1].Style.Width(无效)
ExcelPackage 构造函数不校验文件头,也不做格式预判**。一个被截断的 .xlsx 文件、带 BOM 的 UTF-8 CSV 改后缀、甚至 zip 压缩包,都能让你在 Worksheets[1] 那行得到毫无意义的 NullReferenceException。上线前务必加一层 try/catch (InvalidDataException) 并记录原始文件头字节。










