C# WinForm读取Excel的三种方法及对比详解
作者:墨瑾轩
本文对比分析了三种方法(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数据。
- 从第二行开始读取:通常第一行为标题。
最佳实践建议
- 异步加载:
- 大文件读取时使用
async/await
,避免界面卡顿。
- 大文件读取时使用
- 错误提示:
- 用
try/catch
捕获文件路径错误、格式错误等问题。
- 用
- 日志记录:
- 记录读取过程中的关键信息,方便调试。
- 性能优化:
- 优先选择EPPlus或NPOI,避免Interop的性能瓶颈。
- 用户友好:
- 提供“打开文件”、“保存为CSV”等按钮,提升交互体验。
以上就是C# WinForm读取Excel的三种方法及对比详解的详细内容,更多关于C# WinForm读取Excel的资料请关注脚本之家其它相关文章!