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

 更新时间:2026年05月17日 15:09:38   作者:海盗Sharp  
MiniExcel是一个轻量级库,通过操作ZIP文件实现Excel读写,无需Office环境,本篇介绍了基本读写(DataTable/List⇄Excel)、写入优化(分批写入大文件)、样式设置(列宽、行高、背景色)及使用模板生成报表等内容,需要的朋友可以参考下

背景介绍

报表绕不开 Excel。传统方案用 Microsoft.Office.Interop,需要安装 Office,且进程管理复杂。MiniExcel 是一个轻量级库(< 1MB),通过直接操作 ZIP 压缩包(.xlsx 本质是 ZIP)实现读写,无需 Office 环境,支持 .NET Core / .NET Framework。

本篇覆盖:

  • 基本读写(DataTable / List ⇄ Excel)
  • 写入优化(避免内存膨胀)
  • 样式设置(列宽、行高、背景色)

代码实现

1. 安装与基础读写

dotnet add package MiniExcel
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 =====
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.SaveAs("output.xlsx", devices);
    // 指定 sheet 名
    MiniExcel.SaveAs("output.xlsx", devices, sheetName: "生产数据");
}

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

public void WriteLargeFile(string filePath, IEnumerable<ReportRow> rows)
{
    // MiniExcel 默认会把所有数据加载到内存
    // 大数据量时需要分批处理

    var batchSize = 5000;
    var batch = new List<ReportRow>();

    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.SaveAs(stream, batch, printHeader: true);
                    firstBatch = false;
                }
                else
                {
                    // 后续批次:追加到已有 sheet(通过 sheetName)
                    MiniExcel.AppendExcel(stream, batch, sheetName: "Data");
                }
                batch.Clear();
            }
        }

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

public class ReportRow
{
    public string DeviceId { get; set; }
    public DateTime Timestamp { get; set; }
    public double Temperature { get; set; }
    public double Pressure { get; set; }
}

3. 使用模板生成报表

// 报表模板(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<ReportRow>

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

4. 样式设置

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

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

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

// 自定义样式(需要底层操作)
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. 读取时处理合并单元格

public void ReadMergedCells()
{
    // MiniExcel 默认会返回合并单元格的值到每一行
    // 如果需要识别合并区域,手动解析

    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})");
    }
}

到此这篇关于C#中使用MiniExcel读写.xlsx文件的代码实现的文章就介绍到这了,更多相关C# MiniExcel读写.xlsx文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#命名空间与java包的区别分析

    C#命名空间与java包的区别分析

    这篇文章主要介绍了C#命名空间与java包的区别,较为详细的分析了C#命名空间与java包的相同点与不同点,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • C#实现验证码功能

    C#实现验证码功能

    这篇文章主要为大家详细介绍了C#实现验证码功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • 在WinForm应用程序中快速实现多语言的处理的方法

    在WinForm应用程序中快速实现多语言的处理的方法

    在国际化环境下,越来越多的程序需要做多语言版本,这篇文章主要介绍了在WinForm应用程序中快速实现多语言的处理的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2018-07-07
  • C# 图片格式转换的实例代码

    C# 图片格式转换的实例代码

    这篇文章主要介绍了C# 图片格式转换的实例代码,文中讲解非常详细,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下
    2020-08-08
  • Unity输出带点击跳转功能的Log实现技巧详解

    Unity输出带点击跳转功能的Log实现技巧详解

    这篇文章主要为大家介绍了Unity输出带点击跳转功能的Log实现技巧详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 基于C#实现XML文件读取工具类

    基于C#实现XML文件读取工具类

    这篇文章主要介绍了基于C#实现XML文件读取工具类,涉及C#针对XML文件各节点获取的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • c#中抽象类和接口的详细介绍

    c#中抽象类和接口的详细介绍

    这篇文章介绍了c#中抽象类和接口,有需要的朋友可以参考一下
    2013-10-10
  • 比Math类库abs()方法性能更高的取绝对值方法介绍

    比Math类库abs()方法性能更高的取绝对值方法介绍

    这篇文章主要给大家介绍了一种比Math类库abs()方法性能更高的取绝对值方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • 解析C# Console 控制台为什么也会卡死(原因分析)

    解析C# Console 控制台为什么也会卡死(原因分析)

    在分析旅程中,总会有几例控制台的意外卡死导致的生产事故,有经验的朋友都知道,控制台卡死一般是动了快速编辑窗口的缘故,虽然知道缘由,但一直没有时间探究底层原理,市面上也没有对这块的底层原理介绍,昨天花了点时间简单探究了下,感兴趣的朋友一起看看吧
    2023-10-10
  • unity 文件流读取图片与www读取图片的区别介绍

    unity 文件流读取图片与www读取图片的区别介绍

    这篇文章主要介绍了unity 文件流读取图片与www读取图片的对比分析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04

最新评论