Magicodes.IE.IO 的导入和导出 API
Magicodes.IE.IO 是独立的 XLSX 读写实现,不依赖 EPPlus 运行时。它更适合按行读取,以及新建工作簿后的顺序写入;模板渲染、已有文件编辑和完整 Excel 对象模型不在这条路径的范围内。
先安装
dotnet add package Magicodes.IE.IO
最简单的模型不需要额外配置:
public sealed class Foo
{
public string Name { get; set; } = "";
public decimal Value { get; set; }
public DateTime CreatedAt { get; set; }
}
var foos = new[]
{
new Foo { Name = "foo-1", Value = 1.25m, CreatedAt = new DateTime(2026, 1, 1) },
};
先写一个文件
数据已经在内存中,目标又是本地文件时,直接传路径即可:
Xlsx.Write("foo.xlsx", foos);
路径重载会创建并释放内部 FileStream。如果输出目标由调用方管理,例如文件流或 HTTP 响应流,就使用 Stream 重载:
using var stream = File.Create("foo.xlsx");
Xlsx.Write(stream, foos);
Stream 重载不负责释放传入的流。HTTP 响应写出一部分 XLSX 后,后续发生异常也无法把已发送的字节收回;不要再往同一个响应写 JSON 错误信息。
如果需要“成功后才覆盖旧文件”,在外层先写临时文件,成功后再替换目标文件。
返回 byte[]:适合小结果,不适合大文件
如果 API 必须返回字节数组,可以使用:
byte[] bytes = Xlsx.ToBytes(foos);
这个入口会物化整个工作簿和最终的 byte[]。小文件、测试或确实需要字节数组的 API 可以使用它;下载接口和大数据导出通常应直接写入输出流。
可以这样理解:
| 场景 | 建议 API |
|---|---|
| 小文件、单元测试、需要 byte[] | Xlsx.ToBytes |
| 写本地文件 | Xlsx.Write(path, data) |
| 已有文件流或 HTTP 响应流 | Xlsx.Write(stream, data) |
| 调用方已有缓冲区 | Xlsx.Write(IBufferWriter<byte>, data) |
| 数据源本身异步、不能全量物化 | Xlsx.WriteAsync(stream, IAsyncEnumerable<T>) |
| 导入并同步遍历 | Xlsx.Read<T>(stream) |
| 导入并异步遍历 | Xlsx.ReadAsync<T>(stream) |
再看一个最小导入
读取 API 返回惰性枚举,数据会在遍历时映射为行模型:
using var stream = File.OpenRead("foo.xlsx");
var rows = Xlsx.Read<Foo>(stream).ToList();
读取完成时,Reader 默认会关闭输入流。如果同一个流后面还要继续使用,传入 leaveOpen: true。这和导出 Stream 重载的所有权规则正好相反。
配置列名、格式和过滤
默认情况下,列名和顺序由模型属性推断。需要改列名、格式或过滤行时,再配置 ExportProfile<T>:
Xlsx.Write("foo.xlsx", foos, p =>
{
p.Column(x => x.Name, c => c.WithName("Name"));
p.Column(x => x.Value, c => c.WithFormat("0.00"));
p.Where(x => x.Value > 0);
});
ExportProfile<T> 还负责列顺序、隐藏列、样式、冻结表头、合并单元格和超链接。配置会在写入前冻结,后续每一行复用同一份列计划。
异步数据源
数据库查询已经返回 IAsyncEnumerable<T> 时,可以直接交给异步写入:
await Xlsx.WriteAsync(
response.Body,
GetFoosAsync(cancellationToken),
cancellationToken: cancellationToken);
这条路径不要求先把全部记录放进 List<T>。不过输出缓冲、压缩状态、SST 和数据源自己的预取仍会占用内存;“流式”只表示不必由调用方一次性物化全部行。
什么时候打开 AutoSst
字符串重复率高时,可以尝试启用 Shared String Table(SST):
Xlsx.Write("foo.xlsx", foos, p => p.WithAutoSst(true));
实现会抽样判断是否启用 SST。它能减少重复文本,但也要维护全量唯一字符串表。状态、地区、产品名这类重复短文本可以尝试;订单号、时间戳和随机 ID 这类高基数字段默认保持 Inline String 往往更稳。具体规则见第 05 篇。
从旧导出入口迁移
如果项目之前使用 Magicodes.IE 的旧导出抽象,可以先从这些常见入口迁移:
| 旧思路 | Magicodes.IE.IO |
|---|---|
| 导出到路径 | Xlsx.Write(path, data) |
| 导出到 byte[] | Xlsx.ToBytes(data) |
| 导出到响应流 | Xlsx.Write(stream, data) |
| 异步数据源 | Xlsx.WriteAsync(stream, asyncData) |
| 列和格式配置 | ExportProfile<T> |
迁移前需要重新确认:
- 原来的调用方是否依赖完整工作簿一次性驻留内存;
- 输出流的所有权由谁负责释放;
- 原来使用的高级 Excel 特性是否在当前 IO 路径中有对应实现。
大文件优先考虑 Stream 或 IAsyncEnumerable<T>,不要把所有导出都改成 ToBytes。
浙公网安备 33010602011771号