商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C#中使用MiniExcel读写.xlsx文件的代码实现

C#中使用MiniExcel读写.xlsx文件的代码实现

  发布于2026-07-01 阅读(0)

扫一扫,手机访问

不得不说,在报表这件事上,Excel几乎是个绕不过去的坎儿。以前很多人处理Excel文件,第一反应就是Microsoft.Office.Interop——那套方案你得先装Office,而且进程管理稍有不慎就容易出幺蛾子,算是历史遗留的“老办法”了。今天聊的MiniExcel就清爽很多,库文件不到1MB,核心思路是不依赖Office环境,直接操作.xlsx文件底层的ZIP压缩包,读写都在.NET Core或.NET Framework上跑得挺溜。

C#中使用MiniExcel读写.xlsx文件的代码实现

接下来,我们从最基础的读写开始,再到写入优化、样式设置,一步步把常见的操作场景串起来。

代码实现

1. 安装与基础读写

安装方式就是一行命令的事:

dotnet add package MiniExcel

读取Excel文件,MiniExcel提供了几种很直观的方式。可以直接把整个sheet读成List,也可以指定sheet名称,还可以读成DataTable方便后面做筛选。

using MiniExcelLibs;
// ===== 读 Excel =====
public void ReadExcel()
{
    // 读取整个 sheet
    var rows = MiniExcel.Query("report.xlsx").ToList();
    // 读取指定 sheet
    var rows2 = MiniExcel.Query("report.xlsx", sheetName: "Sheet2").ToList();
    // 读取为 DataTable(便于筛选)
    var dt = MiniExcel.QueryAsDataTable("report.xlsx");
    foreach (DataRow row in dt.Rows)
    {
        Console.WriteLine($"{row["DeviceId"]} - {row["Value"]}");
    }
}

写Excel也一样简洁,直接把List丢进去就行,连表头都会自动映射。

// ===== 写 Excel =====
public void WriteSimpleExcel()
{
    var devices = new[]
    {
        new { DeviceId = "INJ001", Temperature = 85.5, Pressure = 1.2 },
        new { DeviceId = "INJ002", Temperature = 82.3, Pressure = 1.1 }
    };
    // 最简单写法:List 直接写
    MiniExcel.Sa veAs("output.xlsx", devices);
    // 指定 sheet 名
    MiniExcel.Sa veAs("output.xlsx", devices, sheetName: "生产数据");
}

2. 写入优化:分批写入大文件

这里有个常见的坑——MiniExcel默认会把所有数据一股脑加载到内存里。数据量小的时候没什么感觉,但一旦到了几十万行,内存就有点吃不消了。

解决办法也不复杂:分批写入。每次处理5000条,第一批负责创建文件并写入表头,后面批次通过AppendExcel追加数据即可。

public void WriteLargeFile(string filePath, IEnumerable rows)
{
    var batchSize = 5000;
    var batch = new List();

    using (var stream = File.Create(filePath))
    {
        bool firstBatch = true;

        foreach (var row in rows)
        {
            batch.Add(row);

            if (batch.Count >= batchSize)
            {
                if (firstBatch)
                {
                    // 第一批:创建文件 + 写入表头
                    stream.Seek(0, SeekOrigin.Begin);
                    MiniExcel.Sa veAs(stream, batch, printHeader: true);
                    firstBatch = false;
                }
                else
                {
                    // 后续批次:追加到已有 sheet(通过 sheetName)
                    MiniExcel.AppendExcel(stream, batch, sheetName: "Data");
                }
                batch.Clear();
            }
        }

        // 处理剩余数据
        if (batch.Count > 0)
        {
            if (firstBatch)
                MiniExcel.Sa veAs(stream, batch, printHeader: true);
            else
                MiniExcel.AppendExcel(stream, batch, sheetName: "Data");
        }
    }
}

3. 使用模板生成报表

很多业务场景下,报表的格式是固定的,只是每次往里面填数据。MiniExcel支持基于模板生成报表——你先把模板Excel准备好,包括标题、列头、合并单元格等格式信息,然后通过Sa veAsByTemplate把数据注入进去。

// 报表模板(template.xlsx)包含:
// - A1: 标题(已合并单元格)
// - A3: 列头(DeviceId, Timestamp, Temperature...)
// - A4 以下:数据区(空着,等我们填充)

public void GenerateFromTemplate()
{
    string templatePath = "template.xlsx";
    string outputPath = "report_20240421.xlsx";

    // 1. 复制模板
    File.Copy(templatePath, outputPath, overwrite: true);

    // 2. 读取模板内容(不覆盖格式)
    var template = MiniExcel.QueryAsDataTable(outputPath);

    // 3. 准备数据
    var data = GetProductionData(); // List

    // 4. 写入数据(从 A4 开始)
    MiniExcel.Sa veAsByTemplate(outputPath, new
    {
        Title = "2024年4月21日 生产报表",
        GenerateDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm"),
        Data = data  // 这个 key 会对应模板中的 Data 区域
    });
}

4. 样式设置

样式的控制上,MiniExcel提供了一些基础能力,比如设置列宽、列名、数字格式。如果需要更深入的样式控制(比如行高、背景色、字体),那就得借助底层操作了。

public void WriteWithStyle()
{
    var rows = new List>
    {
        new Dictionary { ["DeviceId"] = "INJ001", ["Value"] = 85.5 },
        new Dictionary { ["DeviceId"] = "INJ002", ["Value"] = 82.3 }
    };

    // 设置列配置
    var columns = new Dictionary
    {
        ["DeviceId"] = new MiniExcelColumnAttribute { Name = "设备编号", Width = 15 },
        ["Value"] = new MiniExcelColumnAttribute { Name = "测量值", Width = 12, Format = "0.00" }
    };

    // 写入并设置列宽
    MiniExcel.Sa veAs("styled.xlsx", rows, configurations: columns);
}

如果确实需要更精细的样式控制,技术判断是:直接用MiniExcel做简单的样式配置,遇到复杂场景时果断引入ClosedXML或EPPlus来配合使用。

// 自定义样式(需要底层操作)
public void WriteWithCustomStyle(string filePath)
{
    var config = new MiniExcelConfiguration
    {
        SheetName = "Report"
    };

    using var stream = File.Create(filePath);
    stream.Seek(0, SeekOrigin.Begin);

    // MiniExcel 支持通过 .xlsx 的 shared strings 和 styles.xml
    // 完整样式控制建议用 ClosedXML 或 EPPlus
}

5. 读取时处理合并单元格

合并单元格在真实业务数据中很常见,但读取起来有点麻烦。MiniExcel默认会把合并单元格的值复制到每一行,如果你想精准识别哪些区域是合并的,需要手动解析单元格的MergeCount信息。

public void ReadMergedCells()
{
    var cells = MiniExcel.GetCells("merged.xlsx").ToList();

    var mergedRanges = cells
        .Where(c => c.MergeCount > 0)
        .Select(c => new
        {
            c.Value,
            StartRow = c.Row,
            EndRow = c.Row + c.MergeCount - 1,
            StartCol = c.Column,
            EndCol = c.Column + 1  // 简化:默认横向合并
        })
        .ToList();

    foreach (var m in mergedRanges)
    {
        Console.WriteLine($"合并区域: {m.Value} ({m.StartRow}-{m.EndRow})");
    }
}

总的来说,MiniExcel在轻量级、无Office依赖的Excel处理场景里,确实是值得考虑的选择。如果数据量不大、不需要复杂样式,用它就够了;如果需要更精致的报表设计,那配合ClosedXML或EPPlus做样式的深层控制,才是更成熟的实践路径。

本文转载于:https://www.jb51.net/program/3640097jy.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注