C# WinForm读取Excel的三种方法及对比详解

 更新时间:2025年08月25日 09:35:34   作者:墨瑾轩  
本文对比分析了三种方法(Microsoft Interop、EPPlus组件、NPOI)用于读取Excel数据,详细阐述了各自的特点、优势及局限性,并通过代码示例讲解的非常详细,需要的朋友可以参考下

什么是WinForm读取Excel?

想象一下你的程序变成一个“魔法盒子”——点击按钮,它就能“吞掉”Excel文件,再“吐出”整齐的数据!这就是WinForm读取Excel的神奇之处!

核心问题

  • 如何用C#快速读取Excel文件?
  • 为什么有时候程序会报错“找不到文件”?
  • 为什么Excel文件打开后程序卡死?

3种主流方法对比

方法优点缺点
Microsoft Interop功能强大、支持复杂操作需安装Office、性能差
EPPlus无需Office、开源免费仅支持.xlsx格式
NPOI支持.xls/.xlsx、跨平台代码稍复杂

方法1:Microsoft Interop(需安装Office)

1. 准备工作

  • 安装Office(Windows系统必备!)
  • 在Visual Studio中添加引用:Microsoft.Office.Interop.Excel

2. 代码模板

using Excel = Microsoft.Office.Interop.Excel;

public class ExcelReader
{
    public static void ReadExcelFile()
    {
        // 1. 打开文件对话框
        OpenFileDialog openFileDialog = new OpenFileDialog
        {
            Filter = "Excel 文件 (*.xls, *.xlsx)|*.xls;*.xlsx",
            Title = "请选择Excel文件"
        };

        if (openFileDialog.ShowDialog() != DialogResult.OK) return;

        string filePath = openFileDialog.FileName;

        // 2. 创建Excel应用实例
        Excel.Application excelApp = new Excel.Application();
        Excel.Workbook workbook = null;
        Excel.Worksheet worksheet = null;

        try
        {
            // 3. 打开工作簿
            workbook = excelApp.Workbooks.Open(filePath);
            worksheet = workbook.Sheets[1]; // 默认读取第一个工作表

            // 4. 获取已使用范围
            Excel.Range range = worksheet.UsedRange;

            // 5. 遍历单元格
            for (int row = 1; row <= range.Rows.Count; row++)
            {
                for (int col = 1; col <= range.Columns.Count; col++)
                {
                    // 6. 读取单元格值
                    object cellValue = range.Cells[row, col].Value2;
                    Console.Write(cellValue?.ToString() ?? "NULL" + "\t");
                }
                Console.WriteLine();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("读取失败:" + ex.Message);
        }
        finally
        {
            // 7. 释放COM对象(非常重要!)
            if (workbook != null) workbook.Close(false);
            if (excelApp != null) excelApp.Quit();
            ReleaseComObject(worksheet);
            ReleaseComObject(workbook);
            ReleaseComObject(excelApp);
        }
    }

    private static void ReleaseComObject(object obj)
    {
        if (obj != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
    }
}

代码解析

  • OpenFileDialog:让用户选择Excel文件路径。
  • Interop API:通过Workbooks.Open()打开文件,UsedRange获取数据范围。
  • COM对象释放:必须手动释放,否则程序会残留进程!

方法2:EPPlus(无需Office)

1. 准备工作

安装NuGet包:

Install-Package EPPlus

2. 代码模板

using OfficeOpenXml;
using System.IO;

public class EpplusReader
{
    public static void ReadExcelFile()
    {
        OpenFileDialog openFileDialog = new OpenFileDialog
        {
            Filter = "Excel 文件 (*.xlsx)|*.xlsx",
            Title = "请选择Excel文件"
        };

        if (openFileDialog.ShowDialog() != DialogResult.OK) return;

        string filePath = openFileDialog.FileName;

        using (var package = new ExcelPackage(new FileInfo(filePath)))
        {
            // 1. 获取第一个工作表
            ExcelWorksheet worksheet = package.Workbook.Worksheets[0];

            int rowCount = worksheet.Dimension.Rows;
            int colCount = worksheet.Dimension.Columns;

            // 2. 遍历单元格
            for (int row = 1; row <= rowCount; row++)
            {
                for (int col = 1; col <= colCount; col++)
                {
                    // 3. 读取单元格值
                    string cellValue = worksheet.Cells[row, col].Text;
                    Console.Write(cellValue + "\t");
                }
                Console.WriteLine();
            }
        }
    }
}

代码解析

  • ExcelPackage:直接加载文件,无需Office依赖。
  • Dimension:自动获取行列数,省心省力!
  • Text属性:自动处理日期、数字等格式。

方法3:NPOI(兼容.xls/.xlsx)

1. 准备工作

安装NuGet包:

Install-Package NPOI

2. 代码模板

using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.SS.UserModel;

public class NpoiReader
{
    public static void ReadExcelFile()
    {
        OpenFileDialog openFileDialog = new OpenFileDialog
        {
            Filter = "Excel 文件 (*.xls, *.xlsx)|*.xls;*.xlsx",
            Title = "请选择Excel文件"
        };

        if (openFileDialog.ShowDialog() != DialogResult.OK) return;

        string filePath = openFileDialog.FileName;

        IWorkbook workbook = null;

        using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            // 1. 根据文件扩展名选择加载器
            if (filePath.EndsWith(".xls"))
            {
                workbook = new HSSFWorkbook(file); // .xls格式
            }
            else if (filePath.EndsWith(".xlsx"))
            {
                workbook = new XSSFWorkbook(file); // .xlsx格式
            }
        }

        if (workbook == null) return;

        ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表

        // 2. 遍历行
        for (int rowIndex = 0; rowIndex <= sheet.LastRowNum; rowIndex++)
        {
            IRow row = sheet.GetRow(rowIndex);
            if (row == null) continue;

            // 3. 遍历单元格
            for (int colIndex = 0; colIndex < row.LastCellNum; colIndex++)
            {
                ICell cell = row.GetCell(colIndex);
                string cellValue = cell?.ToString() ?? "NULL";
                Console.Write(cellValue + "\t");
            }
            Console.WriteLine();
        }
    }
}

代码解析

  • HSSFWorkbook/XSSFWorkbook:分别处理.xls和.xlsx文件。
  • GetRow/GetCell:灵活获取行和单元格。
  • ToString():自动处理空值和格式。

常见问题与优化技巧

1. 程序运行后卡死?

场景:Interop方法中未正确关闭Excel进程!
解决方案

// 在finally块中强制退出
if (excelApp != null)
{
    excelApp.Quit();
    ReleaseComObject(excelApp);
}

2. 文件路径错误?

场景:用户选择文件后未检查路径合法性!
解决方案

if (!File.Exists(filePath))
{
    MessageBox.Show("文件不存在!");
    return;
}

3. Excel文件打不开?

场景:文件被其他程序占用!
解决方案

try
{
    workbook = excelApp.Workbooks.Open(filePath);
}
catch (Exception ex)
{
    MessageBox.Show("文件被占用,请关闭Excel后再试!");
}

方法对比总结

方法是否需要Office支持格式性能难度
Interop✅ 必须.xls/.xlsx⚠️ 慢🟡 中
EPPlus❌ 不需要.xlsx✅ 快✅ 简单
NPOI❌ 不需要.xls/.xlsx✅ 快🟡 中

实战场景:Excel数据导入DataGridView

private void ImportToDataGridView(string filePath)
{
    dataGridView1.Rows.Clear();
    dataGridView1.Columns.Clear();

    using (var package = new ExcelPackage(new FileInfo(filePath)))
    {
        var worksheet = package.Workbook.Worksheets[0];
        int colCount = worksheet.Dimension.Columns;

        // 添加列头
        for (int col = 1; col <= colCount; col++)
        {
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = worksheet.Cells[1, col].Text
            });
        }

        // 添加数据行
        for (int row = 2; row <= worksheet.Dimension.Rows; row++)
        {
            var cells = new List<string>();
            for (int col = 1; col <= colCount; col++)
            {
                cells.Add(worksheet.Cells[row, col].Text);
            }
            dataGridView1.Rows.Add(cells.ToArray());
        }
    }
}

代码解析

  • DataGridView绑定:动态创建列和行,实时显示Excel数据。
  • 从第二行开始读取:通常第一行为标题。

最佳实践建议

  1. 异步加载
    • 大文件读取时使用async/await,避免界面卡顿。
  2. 错误提示
    • try/catch捕获文件路径错误、格式错误等问题。
  3. 日志记录
    • 记录读取过程中的关键信息,方便调试。
  4. 性能优化
    • 优先选择EPPlus或NPOI,避免Interop的性能瓶颈。
  5. 用户友好
    • 提供“打开文件”、“保存为CSV”等按钮,提升交互体验。

以上就是C# WinForm读取Excel的三种方法及对比详解的详细内容,更多关于C# WinForm读取Excel的资料请关注脚本之家其它相关文章!

相关文章

  • C#使用Lazy实现延迟加载的方法示例

    C#使用Lazy实现延迟加载的方法示例

    在C#中,Lazy< T> 类是一个非常有用的工具,它可以用于延迟加载值,在本文中,我们将详细介绍 Lazy< T> 的实现机制和用法,并提供一些示例来展示它的优势,文中通过代码示例讲解的非常详细,需要的朋友可以参考下
    2024-06-06
  • C#实现char字符数组与字符串相互转换的方法

    C#实现char字符数组与字符串相互转换的方法

    这篇文章主要介绍了C#实现char字符数组与字符串相互转换的方法,结合实例形式简单分析了C#字符数组转字符串及字符串转字符数组的具体实现技巧,需要的朋友可以参考下
    2017-02-02
  • C#中的引用类型以及特殊引用类型详解

    C#中的引用类型以及特殊引用类型详解

    本文详细讲解了C#中的引用类型以及特殊引用类型,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • C#使用正则表达式过滤html标签

    C#使用正则表达式过滤html标签

    最近在开发一个项目,其中有需求要求我们把一段html转换为一般文本返回,使用正则表达式是明智的选择,下面小编给介绍下C#使用正则表达式过滤html标签,需要的朋友参考下
    2016-08-08
  • 基于C#实现的三层架构实例

    基于C#实现的三层架构实例

    这篇文章主要介绍了基于C#实现的三层架构实例,非常实用,需要的朋友可以参考下
    2014-08-08
  • c# 面试必备线程基础知识点

    c# 面试必备线程基础知识点

    这篇文章主要介绍了c# 面试必备线程基础知识点,帮助大家更好的巩固,掌握线程的基础知识,感兴趣的朋友可以了解下
    2020-11-11
  • C#图像伪彩色处理方法

    C#图像伪彩色处理方法

    这篇文章主要介绍了C#图像伪彩色处理方法,涉及C#操作图像的伪彩色相关技巧,需要的朋友可以参考下
    2015-04-04
  • C#函数out多个返回值问题

    C#函数out多个返回值问题

    这篇文章主要介绍了C#函数out多个返回值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • C#通过抽象工厂模式造车

    C#通过抽象工厂模式造车

    这篇文章介绍了C#通过抽象工厂模式造车的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • Unity Shader实现裁切效果

    Unity Shader实现裁切效果

    这篇文章主要为大家详细介绍了Unity Shader实现裁切效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04

最新评论