1.miniexcel背景简介
常工作中经常与数据打交道的同学肯定会难以避免对Excel的一些数据操作如导入、导出等,但是当对一些大数据量操作Excel时经常会遇到一个常见的问题内存溢出。今天给大家推荐一个简单、高效、低内存避免OOM(内存溢出)的.NET操作Excel开源框架:MiniExcel。
MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。目前主流框架大多需要将数据全载入到内存方便操作,但这会导致内存消耗问题,MiniExcel 尝试以 Stream 角度写底层算法逻辑,能让原本1000多MB占用降低到几MB,避免内存不够情况。
[gitee地址](https://gitee.com/dotnetchina/MiniExcel?_from=gitee_search#getstart1)
2.特点
- 低内存耗用,避免OOM、频繁 Full GC 情况。
- 支持即时操作每行数据。
- 兼具搭配 LINQ 延迟查询特性,能办到低消耗、快速分页等复杂查询。
- 轻量,不需要安装 Microsoft Office、COM+,DLL小于150KB。
- 简便操作的 API 风格。
3.主流Excel操作框架性能对比
导入、查询 Excel 比较
导出、创建 Excel 比较
4.使用经验示例
下面记录一些我自己项目中使用的经验和例子。
首先是查询:
var rows = MiniExcel.Query<ImportOrganizations>(path);
public class ImportOrganizations
{
[ExcelColumnName("企业名称")]
public string OrganizationName { get; set; }
[ExcelColumnName("统一社会信用代码")]
public string CreditCode { get; set; }
[ExcelColumnName("联系人")]
public string ContactPersonName { get; set; }
[ExcelColumnName("联系人手机")]
public string ContactPersonTel { get; set; }
[ExcelColumnName("企业类型")]
public string OrganizationTypes { get; set; }
}
ExcelColumnName可以加列名,中国肯定是中文的表头,这点使用起来就很方便了。
query的参数path这里需要注意一下,这个path是本地的路径,如果是远程的链接路径是 打不开的,这里翻看了底层代码,实际上使用的还是system.io 下的File.Open,File.Open注定了只能读取本地文件了。
这里还有个折中方案,就是先下载下来再去读下载下来的文件然后导入到库里。
public static void SaveAsLocal(IFormFile file)
{
using (var stream = file.OpenReadStream())
{
MiniExcel.SaveAs($"DownloadFile/{Guid.NewGuid()}_{file.FileName}", stream.GetReader(),configuration:new OpenXmlConfiguration(){AutoFilter = false});
}
}
对于我们来说大多数还是传的文件流来读取文件(IFormFile file形式)。
我们 来看一种写法:
public static List<T> GetList<T>(IFormFile file)
{
using (var stream = file.OpenReadStream())
{
var list = stream.Query().Cast<T>().ToList();
return list;
}
}
Query支持Cast方法,按说可以转换为对象,但是这里我封装的这个泛型方法并没有好使,报错了。不得已我只能单独读取:
var rows = new List<ImportOrganizations>();
using (var stream = file.OpenReadStream())
{
rows = (await stream.QueryAsync<ImportOrganizations>()).ToList();
}
这样读取出来就不报错了,不知道为什么,暂时认定为miniexcel的bug。
获取excel表头值:
using (var stream = file.OpenReadStream())
{
var columns = stream.GetColumns(useHeaderRow:true);//方式1
}
var row2 = MiniExcel.Query(templateFilePath).Cast<IDictionary<string,object>>().First();//方式2
上面是两种获取的方式,templateFilePath是文件路径。
获取sheet页
using (var stream = file.OpenReadStream())
{
var sheetNames = stream.GetSheetNames();
}
导出:
public static FileStreamResult SaveAs(object value, string fileName)
{
var memoryStream = new MemoryStream();
memoryStream.SaveAs(value,configuration: new OpenXmlConfiguration() { AutoFilter = false });
memoryStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
FileDownloadName = fileName
};
}
value就是导出的list,fileName文件名称。AutoFilter=false是指导出的excel文件默认不加筛选。
导出完后可以调用一下SaveAs方法,将文件报存到服务器 (本地):
MiniExcel.SaveAs($"DownloadFile/{Guid.NewGuid()}_{file.FileName}",rows):
rows是我们上面query后的list。