.NET 轻量级处理 Excel 文件库 - MiniExce
MiniExcel 是一个轻量级、高性能的 .NET 库,专门用于处理 Excel 文件(如 .xlsx、.xls)和 CSV 文件。它最大的优点是低内存消耗,采用流式处理避免内存溢出(OOM),特别适合处理大文件,同时 API 设计简洁易用。
下面我会详细解释它的核心操作,并举例说明。
📊 MiniExcel 简介与特点
MiniExcel 旨在以简单高效的方式处理 Excel 和 CSV 文件,尤其擅长处理大规模数据而无需担心内存问题。它通过流式处理(Stream-based)机制,使得即使处理大型文件,内存占用也能保持在较低水平。
🔧 安装与准备
首先,你需要通过 NuGet 安装 MiniExcel 包:
- 在 Visual Studio 中,右键单击你的项目 -> “管理 NuGet 程序包”。
- 在浏览选项卡中搜索 “MiniExcel”。
- 选择并点击“安装”。
安装完成后,在你的 C# 代码文件中添加 using 语句:
using MiniExcelLibs;
📖 读取 Excel 文件
MiniExcel 提供了多种读取 Excel 数据的方式,包括匿名查询、强类型查询以及动态查询,非常灵活。
1. 强类型读取(推荐)
如果 Excel 文件的第一行是列名,并且你能用 C# 类定义其结构,这种方式最方便。
// 1. 定义对应的数据模型类
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Value { get; set; }
}
// 2. 读取文件并自动映射到模型列表
string filePath = "people.xlsx";
IEnumerable<Person> people = MiniExcel.Query<Person>(filePath);
foreach (var person in people)
{
Console.WriteLine($"ID: {person.Id}, Name: {person.Name}, Description: {person.Description}, Value: {person.Value}");
}
这种方式要求 Excel 中的列名(首行)与你 C# 类的属性名完全匹配(默认不区分大小写)。
2. 动态类型读取
当你不确定列结构,或者想快速读取时,可以用动态类型 dynamic
。
// 读取所有行,每一行都是一个动态对象
var rows = MiniExcel.Query(filePath, useHeaderRow: true).ToList();
foreach (var row in rows)
{
// 通过列名访问数据(假设Excel第一行有"Id", "Name"等列名)
Console.WriteLine($"ID: {row.Id}, Name: {row.Name}");
// 也可以通过索引器方式访问(如果列名包含空格或特殊字符,这种方式更安全)
// Console.WriteLine($"ID: {row["Id"]}, Name: {row["Name"]}");
}
参数 useHeaderRow: true
告诉 MiniExcel 第一行是标题行。
3. 查询特定工作表
默认查询第一个工作表。你也可以指定工作表名称:
IEnumerable<Person> people = MiniExcel.Query<Person>(filePath, sheetName: "Sheet2");
4. 读取为 DataTable
如果需要与旧代码交互,也可以读取为 DataTable
。
// 创建一个DataTable对象并添加数据
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Rows.Add(1, "Jack");
dt.Rows.Add(2, "Tom");
dt.Rows.Add(3, "Mary");
// 读取Excel文件到DataTable
DataTable dataTable = MiniExcel.QueryAsDataTable(filePath);
💾 写入 Excel 文件
MiniExcel 同样提供了多种方式来写入数据。
1. 写入强类型对象集合(推荐)
这是最常见的方式,将一个对象集合写入 Excel。
// 准备一些数据
List<Person> people = new List<Person>
{
new Person { Id = 1, Name = "Alice", Description = "Developer", Value = 100.5 },
new Person { Id = 2, Name = "Bob", Description = "Designer", Value = 85.3 },
new Person { Id = 3, Name = "Charlie", Description = "Manager", Value = 200.0 }
};
// 写入到文件
string outputPath = "output.xlsx";
MiniExcel.SaveAs(outputPath, people);
Console.WriteLine("Excel文件已保存!");
2. 写入匿名对象或数组
你也可以使用匿名对象或者直接使用对象数组来写入数据。
// 使用匿名对象
var data = new[]
{
new { Column1 = "A", Column2 = 10 },
new { Column1 = "B", Column2 = 20 }
};
MiniExcel.SaveAs("anonymous.xlsx", data);
// 或者使用对象数组(List<object[]>)
var dataArray = new List<object[]>
{
new object[] { "Name", "Age", "City" }, // 标题行
new object[] { "John", 25, "New York" },
new object[] { "Jane", 30, "London" }
};
MiniExcel.SaveAs("fromArray.xlsx", dataArray);
3. 追加数据到现有文件
注意:MiniExcel 的主要 SaveAs
方法通常会覆盖现有文件。如果你想向现有文件(尤其是 CSV)追加数据,可以使用 Insert
方法(此方法对 .xlsx
格式的支持可能有限,更适用于 CSV)。
// 假设我们已经有一个 'data.csv' 文件,里面有一些数据
var newData = new List<Person>
{
new Person { Id = 4, Name = "David", Description = "Tester", Value = 95.7 }
};
// 追加数据到CSV文件末尾
MiniExcel.Insert("data.csv", newData);
对于 .xlsx
格式,如果需要复杂的追加操作,可能需要先读取原有数据,合并后再整体写入。
🎨 样式设置(基础)
MiniExcel 主要关注数据和性能,样式设置功能相对基础。但它仍然支持一些简单的样式。
using MiniExcelLibs;
// 创建一个DataTable
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Rows.Add(1, "Jack");
dt.Rows.Add(2, "Tom");
// 创建 Workbook 对象
var workbook = new MiniExcel.Workbook();
// 设置字体样式
var font = new MiniExcel.Font("Arial", 12);
var style = new MiniExcel.CellStyle { Font = font };
// 将数据与样式添加到 Worksheet
workbook.TryAddWorksheet(dt, "Sheet1", style);
// 保存
workbook.Save("styled_output.xlsx");
请注意,MiniExcel 的样式 API 可能不如 NPOI 或 ClosedXML 等库丰富。
⚠️ 处理特殊情况
空值和类型转换
使用 dynamic
查询时,要注意单元格可能为 null
。最好进行空值检查和处理。
public string DynamicToString(dynamic data)
{
return data == null ? string.Empty : data.ToString();
}
var rows = MiniExcel.Query(filePath, useHeaderRow: true).ToList();
foreach (var row in rows)
{
string name = DynamicToString(row.Name);
// ... 使用 name
}
性能考量
得益于流式处理,MiniExcel 在处理大型文件时内存占用远低于许多传统库(如 NPOI 的 XSSFWorkbook
)。如果你的应用场景涉及大量数据,MiniExcel 是一个非常好的选择。
📌 总结
下表对比了 MiniExcel 的主要操作方式:
操作类型 | 方法名 | 适用场景 | 特点 |
---|---|---|---|
读取 | Query<T>() |
强类型读取,结构固定的Excel | 自动映射,代码清晰 |
Query() (动态) |
快速读取,结构不固定或未知 | 灵活,但需注意类型转换 | |
QueryAsDataTable() |
需与ADO.NET或旧代码交互 | 返回DataTable | |
写入 | SaveAs() |
将对象集合或数组写入新文件 | 覆盖已存在文件 |
Insert() |
主要向CSV文件末尾追加数据 | 对xlsx支持有限 | |
样式 | Workbook /CellStyle |
设置基础单元格样式(如字体) | 功能相对基础 |
💡 核心要点:
- 首选强类型:如果数据结构明确,使用
Query<T>
和SaveAs
配合模型类是最安全、最清晰的方式。 - 动态类型的处理:使用
dynamic
时,要注意空值和类型转换,建议封装辅助方法。 - 追加数据:向现有文件追加数据时,CSV 格式配合
Insert
方法更合适;XLSX 格式可能需要手动合并数据。 - 样式局限性:如果需要复杂的单元格格式、公式或图表,MiniExcel 可能无法满足,可以考虑 NPOI 或 ClosedXML 等更强大的库。
- 大文件利器:MiniExcel 的核心优势在于其低内存消耗和流式处理,非常适合处理大型 Excel/CSV 文件。