.NET 中高效 Excel 解决方案 MiniExcel
前言
MiniExcel 是一个用于 .NET 平台的轻量级、高性能的库,专注于提供简单易用的 API 来处理 Excel 文件。以下是 MiniExcel 的特点总结:
轻量级与高效:MiniExcel 设计为占用较少的系统资源,尤其在内存使用上表现优秀,适合处理大数据集而不会导致内存溢出。
简单易用:API 设计直观,易于理解和使用,即使是初学者也能迅速上手,进行 Excel 数据的读取和写入操作。
快速读写:MiniExcel 提供了快速的数据读写机制,能够有效提高处理 Excel 文件的效率,特别是在大数据量场景下。
灵活的数据处理:支持多种数据类型,包括但不限于数字、文本、日期等,并提供了数据转换和格式化功能。
数据填充:MiniExcel 支持数据填充,可以将数据模板与数据集合相结合,快速生成大量格式化的 Excel 报告。
模板支持:利用模板,可以轻松创建带有预设样式和布局的复杂 Excel 文档,减少重复工作。
跨平台兼容性:MiniExcel 在 .NET Standard 下运行良好,意味着它可以在多个平台上使用,包括 Windows、macOS 和 Linux。
易于集成:可以轻松地将 MiniExcel 集成到现有的 .NET 项目中,无论是 Web 应用、桌面应用还是服务端应用。
MiniExcel 是处理 Excel 文件的理想选择,尤其是对于那些寻求在 .NET 应用中实现快速、低内存消耗的 Excel 数据读写功能的开发者。无论是用于数据分析、报告生成还是数据导入导出,MiniExcel 都能提供强大的支持。
项目介绍
MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。
目前主流框架大多需要将数据全载入到内存方便操作,但这会导致内存消耗问题,MiniExcel 尝试以 Stream 角度写底层算法逻辑,能让原本1000多MB占用降低到几MB,避免内存不够情况。

处理Excel性能对比
1、导入、查询 Excel 比较

2、导出、创建 Excel 比较

安装 MiniExcel
可以查看NuGet命令
https://www.nuget.org/packages/MiniExcel
dotnet add package MiniExcel --version 1.34.0

1、Query 查询 Excel 返回强型别 IEnumerable 数据
public class UserAccount
{
public Guid ID { get; set; }
public string Name { get; set; }
public DateTime BoD { get; set; }
public int Age { get; set; }
public bool VIP { get; set; }
public decimal Points { get; set; }
} var rows = MiniExcel.Query<UserAccount>(path);

2、 Query 查询 Excel 返回Dynamic IEnumerable 数据
Key 系统预设为 A,B,C,D...Z
| MiniExcel | 1 |
Github |
2 |
var rows = MiniExcel.Query(path).ToList(); // or
using (var stream = File.OpenRead(path))
{
var rows = stream.Query().ToList(); Assert.Equal("MiniExcel", rows[0].A);
Assert.Equal(1, rows[0].B);
Assert.Equal("Github", rows[1].A);
Assert.Equal(2, rows[1].B);
}
3、查询数据以第一行数据当Key
注意 : 同名以右边数据为准
Input Excel :
| Column1 | Column2 |
| MiniExcel | 1 |
| Github | 2 |
var rows = MiniExcel.Query(useHeaderRow:true).ToList(); // or using (var stream = File.OpenRead(path))
{
var rows = stream.Query(useHeaderRow:true).ToList(); Assert.Equal("MiniExcel", rows[0].Column1);
Assert.Equal(1, rows[0].Column2);
Assert.Equal("Github", rows[1].Column1);
Assert.Equal(2, rows[1].Column2);
}
4、Query 查询支援延迟加载(Deferred Execution),能配合LINQ First/Take/Skip办到低消耗、高效率复杂查询
举例 : 查询第一笔数据
var row = MiniExcel.Query(path).First();
Assert.Equal("HelloWorld", row.A);
// or
using (var stream = File.OpenRead(path))
{
var row = stream.Query().First();
Assert.Equal("HelloWorld", row.A);
}
5、查询指定 Sheet 名称
MiniExcel.Query(path, sheetName: "SheetName");
//or
stream.Query(sheetName: "SheetName");
6、查询所有 Sheet 名称跟数据
var sheetNames = MiniExcel.GetSheetNames(path);
foreach (var sheetName in sheetNames)
{
var rows = MiniExcel.Query(path, sheetName: sheetName);
}
7、查询所有栏(列)
var columns = MiniExcel.GetColumns(path); // e.g result : ["A","B"...] or var columns = MiniExcel.GetColumns(path, useHeaderRow: true);
// e.g result : ["excel表实际的列名称","excel表实际的列名称"...] var cnt = columns.Count; // get column count
8、Dynamic Query 转成 IDictionary<string,object> 数据
foreach(IDictionary<string,object> row in MiniExcel.Query(path))
{
//..
}
// or
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();
// or 查询指定范围(要大写才生效哦)
// A2(左上角)代表A列的第二行,C3(右下角)代表C列的第三行
// 如果你不想限制行,就不要包含数字
var rows = MiniExcel.QueryRange(path, startCell: "A2", endCell: "C3").Cast<IDictionary<string, object>>();
9、Query 读 Excel 返回 DataTable
提醒 : 不建议使用,因为DataTable会将数据全载入内存,失去MiniExcel低内存消耗功能。
var table = MiniExcel.QueryAsDataTable(path, useHeaderRow: true);
10、指定单元格开始读取数据
MiniExcel.Query(path,useHeaderRow:true,startCell:"B3")
11、合并的单元格填充
注意 : 效率相对于没有使用合并填充来说差
底层原因 : OpenXml 标准将 mergeCells 放在文件最下方,导致需要遍历两次 sheetxml
var config = new OpenXmlConfiguration()
{
FillMergedCells = true
};
var rows = MiniExcel.Query(path, configuration: config);
12、读取大文件硬盘缓存 (Disk-Base Cache - SharedString)
概念 : MiniExcel 当判断文件 SharedString 大小超过 5MB,预设会使用本地缓存,如 10x100000.xlsx(一百万笔数据),读取不开启本地缓存需要最高内存使用约195MB,开启后降为65MB。
但要特别注意,此优化是以时间换取内存减少,所以读取效率会变慢,此例子读取时间从 7.4 秒提高到 27.2 秒,假如不需要能用以下代码关闭硬盘缓存
var config = new OpenXmlConfiguration { EnableSharedStringCache = false };
MiniExcel.Query(path,configuration: config)
也能使用 SharedStringCacheSize 调整 sharedString 文件大小超过指定大小才做硬盘缓存
var config = new OpenXmlConfiguration { SharedStringCacheSize=500*1024*1024 };
MiniExcel.Query(path, configuration: config);
写/导出 Excel
必须是非abstract 类别有公开无参数构造函数
MiniExcel SaveAs 支援 IEnumerable参数延迟查询,除非必要请不要使用 ToList 等方法读取全部数据到内存
是否呼叫 ToList 的内存差别,如下图所示:

1、支持集合<匿名类别>或是<强型别>
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
MiniExcel.SaveAs(path, new[] {
new { Column1 = "MiniExcel", Column2 = 1 },
new { Column1 = "Github", Column2 = 2}
});
2、IEnumerable<IDictionary<string, object>>
var values = new List<Dictionary<string, object>>()
{
new Dictionary<string,object>{{ "Column1", "MiniExcel" }, { "Column2", 1 } },
new Dictionary<string,object>{{ "Column1", "Github" }, { "Column2", 2 } }
};
MiniExcel.SaveAs(path, values);
3、IDataReader
推荐使用,可以避免载入全部数据到内存 MiniExcel.SaveAs(path, reader);

推荐 DataReader 多表格导出方式(建议使用 Dapper ExecuteReader )
using (var cnn = Connection)
{
cnn.Open();
var sheets = new Dictionary<string,object>();
sheets.Add("sheet1", cnn.ExecuteReader("select 1 id"));
sheets.Add("sheet2", cnn.ExecuteReader("select 2 id"));
MiniExcel.SaveAs("Demo.xlsx", sheets);
}
4、Datatable
不推荐使用,会将数据全载入内存
优先使用 Caption 当栏位名称
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
var table = new DataTable();
{
table.Columns.Add("Column1", typeof(string));
table.Columns.Add("Column2", typeof(decimal));
table.Rows.Add("MiniExcel", 1);
table.Rows.Add("Github", 2);
}
MiniExcel.SaveAs(path, table);
5、Dapper Query
6、SaveAs 支持 Stream,生成文件不落地
7、创建多个工作表(Sheet)
8、表格样式选择
9、AutoFilter 筛选
10、图片生成
11、Byte Array 文件导出
12、垂直合并相同的单元格
13、是否写入 null values cell
模板填充 Excel
1、基本填充
2、IEnumerable 数据填充
3、复杂数据填充
4、大数据填充效率比较
5、Cell 值自动类别对应
6、Example : 列出 Github 专案

var projects = new[]
{
new {Name = "MiniExcel",Link="https://github.com/shps951023/MiniExcel",Star=146, CreateTime=new DateTime(2021,03,01)},
new {Name = "HtmlTableHelper",Link="https://github.com/shps951023/HtmlTableHelper",Star=16, CreateTime=new DateTime(2020,02,01)},
new {Name = "PocoClassGenerator",Link="https://github.com/shps951023/PocoClassGenerator",Star=16, CreateTime=new DateTime(2019,03,17)}
};
var value = new
{
User = "ITWeiHan",
Projects = projects,
TotalStar = projects.Sum(s => s.Star)
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);
8、DataTable 当参数
地址
https://gitee.com/dotnetchina/MiniExcel
如果觉得这篇文章对你有用,欢迎加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行交流心得,共同成长。

.NET 中高效 Excel 解决方案 MiniExcel的更多相关文章
- 【转】js 中导出excel 较长数字串会变为科学计数法
[转]js 中导出excel 较长数字串会变成科学计数法 在做项目中,碰到如题的问题.比如要将居民的信息导出到excel中,居民的身份证号码因为长度过长(大于10位),excel会自动的将过长的数字串 ...
- VSTO之旅系列(二):创建Excel解决方案
原文:VSTO之旅系列(二):创建Excel解决方案 本专题概要 引言 创建VSTO项目 Excel对象模型 创建Excel外接程序 创建Excel文档级自定义项 小结 一.引言 也许很多朋友都没有听 ...
- 如何在单独的窗口中打开 Excel 文件
如何在单独的窗口中打开 Excel 文件 文章编号:087583 2012/11/1 18:45:29 故障现象: 如何在单独的窗口中打开 Excel 文件? 解决方案: 比较安全的方法就是直 ...
- 在VBA中调用excel函数
以前不太会用VBA时,都是在excel中使用函数来计算一些数据.毕竟函数不如代码,效率比较低.所以,就学着怎么在VBA中引用Excel函数.平时我用得比较多的函数就是countif和sumif函数.1 ...
- UpdatePanel 中 导出Excel按钮
UpdatePanel 中 导出Excel按钮 要加 Triggers </ContentTemplate> <Triggers> <asp:PostBackTrigge ...
- asp.net中导出Excel的方法
一.asp.net中导出Excel的方法: 本文转载 在asp.net中导出Excel有两种方法,一种是将导出的文件存放在服务器某个文件夹下面,然后将文件地址输出在浏览器上:一种是将文件直接将文件输出 ...
- ASP.net中导出Excel的简单方法介绍
下面介绍一种ASP.net中导出Excel的简单方法 先上代码:前台代码如下(这是自己项目里面写的一点代码先贴出来吧) <div id="export" runat=&quo ...
- 在Unity中高效工作(下)
原地址:http://www.unity蛮牛.com/thread-20005-1-1.html Tips for Creating Better Games and Working More Eff ...
- 报表中的Excel操作之Aspose.Cells(Excel模板)
原文:报表中的Excel操作之Aspose.Cells(Excel模板) 本篇中将简单记录下Aspose.Cells这个强大的Excel操作组件.这个组件的强大之处,就不多说,对于我们的报表总是会有导 ...
- C#中对Excel进行操作
工作中要处理一批数据,主要是处理从别处导出来的Excel表格(大概有一千多行,三十多列),拿到表格对Excel表格进行分析,按照一定的规则进行拆分成为一万多行的数据:首先这个需求要用程序进行处理的背景 ...
随机推荐
- 2024 FIC取证比赛wp(更新中)
本次竞赛容器挂载密码为: 2024Fic@杭州Powered~by~HL! 2024年4月,卢某报案至警方,声称自己疑似遭受了"杀猪盘"诈骗,大量钱财被骗走.卢某透露,在与某公司交 ...
- Android 13 - Media框架(1)- 总览
关注公众号免费阅读全文,进入音视频开发技术分享群! 为了加深对Android Media框架的理解,决定在这里记录下学习过程中碰到的问题以及一些个人思考.由于本人水平有限,笔记的内容可能会有一些错误, ...
- 深入理解Vue 3:计算属性与侦听器的艺术
title: 深入理解Vue 3:计算属性与侦听器的艺术 date: 2024/5/30 下午3:53:47 updated: 2024/5/30 下午3:53:47 categories: 前端开发 ...
- itest(爱测试) 开源接口测试,敏捷测试管理平台10.0.0GA 发布
一:itest work 简介 itest work 开源敏捷测试管理,包含极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock,还有压测 ,又有丰富的统计分析,8合1工作站.可按 ...
- LiteOS基础学习
1 IDE环境安装 目的:安装LiteOS IDE,并且是使用仿真方式运行. 1.1 IDE安装 HUAWEI LiteOS Studio安装 (gitee.io) 1.2 中文安装 HUAWEI L ...
- 使用Wesky.Net.Opentools库,一行代码实现自动解析实体类summary注释信息(可用于数据实体文档的快速实现)
使用前,需要对你的项目勾选输出api文档文件. 引用Wesky.Net.OpenTools包,保持1.0.11版本或以上. 为了方便,我直接在昨天的演示基础上,继续给实体类添加注释. 昨天的演示文 ...
- margin的用法 清除默认样式 display属性值 块状元素 内联元素 行内块元素
margin的用法: 1,margin是在元素的宽高以外的 2,作用:控制元素之间的位置关系 3,margin不能改变盒子本身大小的 4,单一一个方向设置margin值: margin-left ...
- memo(自带)
React.memo()是一个高阶函数,它与 React.PureComponent类似,但是一个函数组件而非一个类.如果你的组件在相同 props的情况下渲染相同的结果,那么你可以通过将其包装在 R ...
- react组件传值(props[只读属性]) 函数组件
组件间传值,在React中是通过只读属性 props 来完成数据传递的. props:接受任意的入参,并返回用于描述页面展示内容的 React 元素. function Cmp1(props) { r ...
- OAuth + Security - 2 - 资源服务器配置
PS:此文章为系列文章,建议从第一篇开始阅读. 资源服务器配置 @EnableResourceServer 注解到一个@Configuration配置类上,并且必须使用ResourceServerCo ...