.NET 轻量级处理 Excel 文件库 - MiniExce

发布于:2025-09-13 ⋅ 阅读:(18) ⋅ 点赞:(0)

MiniExcel 是一个轻量级、高性能的 .NET 库,专门用于处理 Excel 文件(如 .xlsx、.xls)和 CSV 文件。它最大的优点是低内存消耗,采用流式处理避免内存溢出(OOM),特别适合处理大文件,同时 API 设计简洁易用。

下面我会详细解释它的核心操作,并举例说明。

📊 MiniExcel 简介与特点

MiniExcel 旨在以简单高效的方式处理 Excel 和 CSV 文件,尤其擅长处理大规模数据而无需担心内存问题。它通过流式处理(Stream-based)机制,使得即使处理大型文件,内存占用也能保持在较低水平。

🔧 安装与准备

首先,你需要通过 NuGet 安装 MiniExcel 包:

  1. 在 Visual Studio 中,右键单击你的项目 -> “管理 NuGet 程序包”。
  2. 在浏览选项卡中搜索 “MiniExcel”。
  3. 选择并点击“安装”。

安装完成后,在你的 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 可能无法满足,可以考虑 NPOIClosedXML 等更强大的库。
  • 大文件利器:MiniExcel 的核心优势在于其低内存消耗和流式处理,非常适合处理大型 Excel/CSV 文件。