EPPlus 是 .NET 6+ 项目 Excel 导入导出最稳妥选择;纯托管、零依赖、API 直观、MIT 免费商用,支持 .NET Core 3.1+ 及 .NET 5+,但不支持 .xls 旧格式。

用 EPPlus 实现 Excel 导入导出最稳妥,.NET 6+ 项目直接 NuGet 安装 EPPlus 即可开干;别碰 Microsoft.Office.Interop.Excel,它依赖本地 Office、不支持 Linux、极易卡死。
为什么选 EPPlus 而不是 Interop 或 NPOI
Interop 必须装 Excel,服务器部署直接报错 Retrieving the COM class factory for component with CLSID {00024500-0000-0000-C000-000000000046} failed;NPOI API 繁琐,对 .xlsx 支持弱,读写合并单元格、样式、公式容易丢数据。而 EPPlus 纯托管、零依赖、API 直观,且从 6.x 开始免费商用(MIT 协议)。
- 仅支持 .xlsx(不支持 .xls),若必须处理旧格式,先用 LibreOffice 命令行转成 xlsx 再进流程
- .NET Framework 4.5+ 和 .NET Core 3.1+ / .NET 5+ 全支持,但
EPPlus 6+不再支持 .NET Framework 4.6.1 以下版本 - 读大文件(>10 万行)时务必用
LoadFromCollection+AutoFilter = true,否则内存暴涨
导入:用 LoadFromCollection 读 Excel 到 List
别手动遍历 ExcelWorksheet.Cells——易错、慢、难维护。直接让 EPPlus 映射列名到属性名:
var package = new ExcelPackage(new FileInfo("data.xlsx"));
var worksheet = package.Workbook.Worksheets[0];
var data = worksheet.Cells["A1"].LoadFromCollection<user>(users, true); // true 表示首行为标题</user>
- 类
User属性名必须和 Excel 表头文字**完全一致**(忽略大小写,但空格、标点不能差) - 支持
[Column(Order = 1)]特性控制列顺序,也支持[DisplayName("用户姓名")]匹配中文表头 - 空单元格会映射为
null(引用类型)或默认值(值类型),若需跳过整行,得自己加Where(r => !string.IsNullOrWhiteSpace(r.Name))
导出:用 LoadFromCollection 写 List 到 Excel
导出比导入更简单,核心就一行:
worksheet.Cells["A1"].LoadFromCollection(users, true); // true 表示生成表头
- 表头文字默认取属性名,想改用中文就加
[Display(Name = "创建时间")]特性 - 日期列导出后常显示为数字(Excel 底层是浮点数),需手动设格式:
worksheet.Column(3).Style.Numberformat.Format = "yyyy-mm-dd"; - 导出后记得调用
package.SaveAs(new FileInfo("output.xlsx")),别只调Save()(那是内存流)
常见坑:中文乱码、日期变数字、服务器导出失败
乱码基本只发生在用 FileStream 手动写入时没指定 Encoding.UTF8,但 EPPlus 自己处理编码,所以只要不用 File.WriteAllText 搞事就不会乱。真正高频问题是:
-
System.InvalidOperationException: The process cannot access the file because it is being used by another process.—— 没释放ExcelPackage,务必用using或显式调Dispose() - 导出的 Excel 打开提示“发现不可读取的内容”,大概率是某列写了
null但该列类型是DateTime,提前做空值判断或用可空类型DateTime? - Linux 服务器上导出失败,检查是否启用了
System.Drawing.Common(EPPlus 6+ 已移除依赖),若项目里还引用着这个包,删掉
导出逻辑越简单越好,别在 LoadFromCollection 后疯狂调 worksheet.Cells[i,j].Value = ...,那会把性能拉垮,也容易覆盖已有数据。











