Magicodes.IE.IO:零依赖、流式低分配的 .NET Excel 读写库
Magicodes.IE.IO零依赖、流式低分配的 .NET Excel 读写库目录为什么又造一个 Excel 库核心设计哲学五分钟上手与其他 Excel 库的对比高级功能速览与老 Magicodes.IE.Excel 的区别AOT / NativeAOT 支持迁移指南总结为什么又造一个 Excel 库.NET 生态里 Excel 读写方案已经很成熟了——EPPlus、ClosedXML、MiniExcel、NPOI各有各的适用场景。Magicodes.IE.IO 走的是另一条路零运行时依赖从 ZIP 到 OOXML 全部自研不依赖任何第三方 Excel 库。对于类库作者来说这意味着你的 NuGet 包不会因为引用了 Excel 功能就把一整套依赖链带进下游项目。Magicodes.IE 团队在维护老Magicodes.IE.Excel(基于 EPPlus)的过程中吃够了这个苦于是从头实现了一个零运行时依赖、流式低内存、多 TFM 覆盖的 Excel I/O 引擎——Magicodes.IE.IO。dotnet add package Magicodes.IE.IO支持netstandard2.0/net6.0/net8.0/net10.0。net6.0及以上只依赖 BCL。核心设计哲学1. 零运行时依赖不依赖 EPPlus、不依赖 ClosedXML、不依赖任何第三方 Excel 库。net6.0目标只引用 BCLnetstandard2.0只包含少量兼容性 polyfill(System.Text.Encoding.CodePages等)。这意味着不会引入第三方 Excel 库的版本冲突你的类库可以放心引用Magicodes.IE.IO不会让下游被迫引入 Excel 依赖NuGet 包体积极小审计面窄2. 流式低内存写入核心写入路径尽量少分配托管内存。我们不构建 DOM 树、不把整个 workbook 加载到内存再序列化——而是边算边写场景10 万行 4 列分配量同步Write(Stream)~38 ms~72 KB(固定)异步WriteAsync(Stream)~39 ms~92 KB便利层ToBytes()~39 ms~8.5 MB(物化为byte[])换句话说同步流式写的 ~72KB 是固定开销(内部缓冲、ZIP 头、共享字符串字典)与行数无关。1 万行是 68KB10 万行是 72KB——只多了 4.5KB。导 100 万行内存也涨不上去。ToBytes()因需把整个文件物化成byte[]分配随数据量线性增长(10 万行约 8.5 MB)这是设计内权衡。大数据请用Write(Stream)。3. 完整的异步支持// 写支持 IEnumerableT 和 IAsyncEnumerableT await Xlsx.WriteAsync(stream, data); // 已物化集合异步写入 await Xlsx.WriteAsync(stream, GetAsyncData()); // IAsyncEnumerable 边查边写 await Xlsx.WriteAsync(/tmp/orders.xlsx, orders); // 文件路径便利重载 // 读支持同步枚举和异步枚举 var rows Xlsx.ReadOrder(stream).ToList(); await foreach (var o in Xlsx.ReadAsyncOrder(stream)) Console.WriteLine(o.OrderNo);IAsyncEnumerable路径配合 EF Core 的AsAsyncEnumerable()可以从数据库流式读取并直接写入 xlsx不需要先把数据全部读到内存。4. 正确性优先每个导出的 xlsx 都经过三层格式校验必需部件齐全([Content_Types].xml、workbook.xml、sheet1.xml、styles.xml、_rels)所有 XML/rels 均为 well-formedOpenXML 包关系图完整(.rels引用的每个 target 真实存在)同时支持 1900/1904 双日期系统的正确读取(自动归一化)。五分钟上手零配置导出// 写文件 Xlsx.Write(/tmp/orders.xlsx, orders); // 写流(响应给浏览器) Xlsx.Write(Response.Body, orders); // 直接拿到 byte[] var bytes Xlsx.ToBytes(orders);表头 属性名列序 声明序自动识别 string / number / DateTime / bool / enum / struct / record。Fluent Profile 配置var bytes Xlsx.ToBytes(orders, p p .Sheet(订单表) .Column(x x.OrderNo, c c.WithName(订单号).WithWidth(30)) .Column(x x.Amount, c c.WithFormat(0.00)) .Ignore(x x.CreatedAt) .WithFreezeHeader(true));多 SheetXlsx.WriteWorkbook(stream, new SheetOrder(Orders, orders), new SheetItem(Items, items));读取// 同步 var rows Xlsx.ReadOrder(stream).ToList(); // 异步 await foreach (var o in Xlsx.ReadAsyncOrder(stream)) Process(o);属性标注public class Order { [ExporterHeader(Name 订单号, Width 30)] public string OrderNo { get; set; } [DisplayFormat(DataFormatString 0.00)] public decimal Amount { get; set; } [ExporterHeader(IsIgnore true)] public DateTime CreatedAt { get; set; } }标注优先级fluent .WithName()[ExporterHeader][Display(Name)][Description] 属性名。模板导出基于.xlsx模板把单元格里的{{属性名}}占位符替换为数据值{{#集合}}…{{/集合}}列表块逐行展开await Xlsx.ExportByTemplateAsync(template.xlsx, output.xlsx, data);模板原有的样式、合并单元格、图片、公式全部保留。行号、公式引用自动平移。与其他 Excel 库的对比.NET 生态中主流的 Excel 库各有各的侧重点。我们在 BenchmarkDotNet 中跑了Magicodes.IE.IO、EPPlus、MiniExcel、ClosedXML、OpenXML SDK的横向对比。参与者简介库模式依赖特点Magicodes.IE.IO流式无(net6 纯 BCL)自研 ZIP CRC OOXML边算边写MiniExcel流式无轻量性能出色功能克制EPPlus (v5)DOMImageSharp 等功能完整商业授权(v5)ClosedXMLDOM多个API 优雅功能全面OpenXML SDKDOM无微软官方低层 API写入性能对比.NET 10 / Apple M4 / 4 列字符串 × 100k 行(Fastest 压缩)库方法耗时分配Magicodes.IE.IOXlsx.ToBytes()基准30.3 ms8.91 MBMagicodes.IE.IOToBytes() 宽松引用20.4 ms7.14 MBMagicodes.IE.IOSource Gen 快路径21.1 ms3.60 MBMagicodes.IE.IOWrite(Stream)流式~38 ms~72 KBMiniExcelSaveAs()149.2 ms213.69 MBEPPlusExcelPackage.Save()455.3 ms257.31 MBClosedXMLXLWorkbook.SaveAs()678.7 ms805.99 MB与其他库的倍数对比对比速度倍数分配倍数vs MiniExcel4.9x 更快24.0x 更小vs EPPlus15.0x 更快28.9x 更小vs ClosedXML22.4x 更快90.5x 更小上面是ToBytes()便利层的对比。若用流式Write(Stream)Mio 分配仅 ~72KB(固定)与其他库的差距拉到 3000x。基准项目完整覆盖了1k/10k/50k/100k四种数据量、string/number/datetime/boolean/mixed/styled/SST(高重复字符串自动去重)七个维度、Fastest/NoCompression两种压缩档位。完整数字执行dotnet run -c Release -f net10.0 --project src/Magicodes.IE.Benchmarks -- \ --filter *XlsxIO_Benchmarks* --job short --memory快速对比各库优势与适用场景维度Magicodes.IE.IOMiniExcelEPPlusClosedXMLOpenXML SDK运行时依赖⭐⭐⭐ 无⭐⭐⭐ 无⭐ 多个⭐ 多个⭐⭐ 仅 BCL授权MITMIT商业(v5)MITMIT写入内存⭐⭐⭐ 流式 ~72KB⭐⭐⭐ 流式⭐ DOM⭐ DOM⭐ DOM写入速度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐功能完整度⭐⭐ 常用⭐⭐ 轻量⭐⭐⭐ 全面⭐⭐⭐ 全面⭐⭐⭐ 底层异步流⭐⭐⭐ 原生⭐ 有限⭐⭐ Task⭐⭐ Task⭐⭐ TaskAOT/裁剪⭐⭐⭐ SG⭐⭐⭐⭐⭐⭐API 易用性⭐⭐⭐ 单入口⭐⭐⭐ 简洁⭐⭐⭐⭐⭐ 优雅⭐ 底层选型建议类库/NuGet 包作者选Magicodes.IE.IO——零依赖不会给下游带来任何负担轻量导出 / 已有 MiniExcel两者流式性能接近Mio 在异步流和 AOT 上更强复杂格式 / 图表 / 打印 / 高级样式选 EPPlus 或 ClosedXML——功能最全需要底层控制选 OpenXML SDKWeb 应用批量导出 异步流Magicodes.IE.IO的IAsyncEnumerable原生支持是它独有的优势高级功能速览以下功能默认通过XlsxWriter底层 API 调用常用场景建议先看Xlsx.Write()够不够。数据验证(下拉列表)using var writer new XlsxWriter(stream, 订单表); writer.AddDataValidation(new DataValidation(C2:C1000, DataValidationType.List, \已下单,已发货,已完成\));公式Xlsx.ToBytes(items, p p .Column(x x.Qty, c c.WithName(数量)) .Column(x x.Price, c c.WithName(单价)) .Column(x x.Total, c c.WithName(合计) .WithFormula(A{row}*B{row})));{row}自动替换为当前行号(1-based)展开为A2*B2、A3*B3…共享字符串表(SST)对大量重复字符串的大文件自动启用 SST 去重Xlsx.ToBytes(orders, p p.WithAutoSst(true));预扫前 64 行字符串去重比例低于 70% 时自动切到 SST减少文件体积。自动筛选、合并单元格、超链接、行过滤var bytes Xlsx.ToBytes(data, p p .Where(x x.Amount 0) // 只导出符合条件的行 .WithAutoFilter(A1:E1) // 自动筛选 .MergeCells(A1:B1) // 合并单元格 .AddHyperlink(A1, https://...)); // 超链接表格、打印设置、保护、批注、条件格式、大纲见tests/Magicodes.IE.IO.Tests/目录下的完整示例。覆盖了日常常见的 Excel 操作需求。压缩档位// 默认 Fastest Xlsx.ToBytes(data); // 纯 CPU 优先时关闭压缩 Xlsx.ToBytes(data, options: new XlsxWriteOptions { Compression CompressionLevel.NoCompression }); // 文件需要走网络传输、体积优先 Xlsx.ToBytes(data, options: new XlsxWriteOptions { Compression CompressionLevel.Optimal });与老 Magicodes.IE.Excel 的区别维度老Magicodes.IE.Excel新Magicodes.IE.IO第三方依赖EPPlus无(net6 纯 BCL)写入模型DOM 全量构建流式边写边序列化读取EPPlus 封装自研流式 Reader多 Sheet复杂WriteWorkbook(...)一行异步流不支持IAsyncEnumerableT原生支持AOT / 裁剪不友好Source Generator 生成无需反射API 入口多接口多抽象Xlsx.Write()/Xlsx.Read()统一静态入口包体积大极小(net6 零额外依赖)AOT / NativeAOT 支持为 DTO 加一个[XlsxExportable]特性Source Generator 即生成属性 getter、cell writer、列元数据和 cell setter。读写路径完全不碰反射适用于 NativeAOT 和剪裁场景[XlsxExportable] public class Order { public string OrderNo { get; set; } public decimal Amount { get; set; } } // 和普通用法完全一样 var bytes Xlsx.ToBytes(orders);普通 .NET 应用无需标注直接反射即可——这是渐进式的 AOT 支持。迁移指南从老Magicodes.IE.Excel迁移只需三步把services.AddExcelExporter()注册删掉把旧的导出/导入入口替换为Xlsx.Write()/Xlsx.ToBytes()/Xlsx.Read()ExporterHeaderAttribute仍然兼容ExportDtoAttribute不再需要(直接用ExportProfileT的 fluent API)总结Magicodes.IE.IO 解决的核心问题是不引入 Excel 库依赖的前提下提供高性能、低分配的 xlsx 读写能力。特别适合类库 / NuGet 包作者零依赖下游不会因此引入任何 Excel 库Web 应用导出场景流式写入响应流内存峰值恒定大数据导出配合IAsyncEnumerable实现数据库流式查询 → 直接写 xlsxAOT 场景Source Generator 消除反射NativeAOT 友好仓库地址github.com/dotnetcore/Magicodes.IENuGetdotnet add package Magicodes.IE.IO如果对你有帮助欢迎 ⭐ Star。遇到问题或功能建议直接提 Issue。也可以加入 QQ 群 85318032 交流(添加时注明 Magicodes.IE)。许可协议MIT

相关新闻