C#实现Excel文件选择与逐单元格读取(含上下按钮)及代码问题修复
解决Excel逐行读取卡顿、显示最后一条记录及进程残留问题
我来帮你梳理下当前代码的问题,然后给出完整的修复方案:
问题根源分析
- 只显示最后一个单元格值:
你的btnNext_Click方法里每次都把iRow重置为2,而且getExcelData里用了for循环从传入的rowNo一直遍历到最后一行,最后textEnterData.Text会被最后一行的值覆盖,自然看不到中间的记录。 - 程序卡顿+多Excel.exe进程:
每次点击Next按钮,你都会重新创建Excel.Application实例、打开Workbook,但从来没有关闭和释放这些资源。这不仅会导致重复打开文件卡顿,还会让Excel进程一直留在后台,越积越多。
修复方案
我们需要做这几个关键调整:
- 将Excel相关对象(
xlApp,xlWorkBook,xlWorkSheet)提升为类级成员,只初始化一次,避免重复创建。 - 维护一个全局的当前行计数器(比如
_currentRow),记录当前读取的行号,不要每次都重置。 - 移除
getExcelData里的for循环,直接读取当前行的单元格值。 - 添加“上一个单元格”按钮的逻辑,处理行号递减的边界(不能小于数据起始行,比如2)。
- 确保在不再使用Excel时,正确关闭并释放所有资源,杀掉后台进程。
修正后的完整代码
using Excel = Microsoft.Office.Interop.Excel; using System; using System.Windows.Forms; namespace YourNamespace { public partial class YourForm : Form { // 类级变量,只初始化一次 public static string ExcelName = ""; string imagepath; Excel.Application xlApp; Excel.Workbook xlWorkBook; Excel.Worksheet xlWorkSheet; int _currentRow = 2; // 当前读取的行号,默认从第2行开始(假设第1行是表头) int _totalRows; // 记录Excel的总行数 public YourForm() { InitializeComponent(); } private void btnExcel_Click(object sender, EventArgs e) { getExcel(); } private void getExcel() { try { OpenFileDialog folder = new OpenFileDialog(); folder.Title = "Select Excel file"; folder.FileName = ""; folder.Filter = "Excel File|*.xlsx;*.xls"; if (folder.ShowDialog() == DialogResult.OK) { ExcelName = folder.FileName; if (!string.IsNullOrEmpty(ExcelName.Trim())) { textBoxExcel.Text = ExcelName; // 初始化Excel对象,只做一次 InitializeExcel(); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } // 初始化Excel对象,获取总行数 private void InitializeExcel() { try { xlApp = new Excel.Application(); xlWorkBook = xlApp.Workbooks.Open(ExcelName); xlWorkSheet = xlWorkBook.Worksheets["Sheet1"]; Excel.Range xlRange = xlWorkSheet.UsedRange; _totalRows = xlRange.Rows.Count; // 显示第一行数据(第2行) UpdateCurrentRowData(); } catch (Exception ex) { MessageBox.Show(ex.Message); ReleaseExcelResources(); } } // 更新当前行的数据到文本框 private void UpdateCurrentRowData() { if (xlWorkSheet == null) return; // 处理单元格值为空的情况 var cellValue = xlWorkSheet.Cells[_currentRow, 2].Value; textEnterData.Text = cellValue == null ? "" : cellValue.ToString(); textBoxGo.Text = _currentRow.ToString(); } private void btnNext_Click(object sender, EventArgs e) { // 检查是否还有下一行 if (_currentRow < _totalRows) { _currentRow++; UpdateCurrentRowData(); } else { MessageBox.Show("已经是最后一条记录了!"); } } // 添加上一个按钮的点击事件 private void btnPrevious_Click(object sender, EventArgs e) { // 检查是否已经是第一行数据 if (_currentRow > 2) { _currentRow--; UpdateCurrentRowData(); } else { MessageBox.Show("已经是第一条记录了!"); } } private void btnImage_Click(object sender, EventArgs e) { readImgaePath(); } private void label5_Click(object sender, EventArgs e) { } private void readImgaePath() { FolderBrowserDialog imagepathDir = new FolderBrowserDialog(); if (imagepathDir.ShowDialog() == DialogResult.OK) { imagepath = imagepathDir.SelectedPath; textBoxIamge.Text = imagepath; } } // 释放Excel资源,避免进程残留 private void ReleaseExcelResources() { if (xlWorkBook != null) { xlWorkBook.Close(false); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkBook); xlWorkBook = null; } if (xlApp != null) { xlApp.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp); xlApp = null; } } // 窗体关闭时释放资源 protected override void OnFormClosed(FormClosedEventArgs e) { base.OnFormClosed(e); ReleaseExcelResources(); } } }
额外注意事项
- 确保你已经引用了
Microsoft.Office.Interop.Excel程序集。 - 如果你的Excel文件表头不是第1行,可以调整
_currentRow的初始值和btnPrevious_Click里的边界判断。 - 处理单元格值的时候,根据实际数据类型做适当转换,避免
ToString()报错。
内容的提问来源于stack exchange,提问作者chandan sharma
相关产品推荐
相关产品推荐

