如何使用C# ClosedXML遍历行中除最后一个单元格外的所有单元格?
问题根因
插入空白列的方案无效,是因为ClosedXML的RangeUsed()逻辑是计算所有带值/带格式单元格的最小外接矩形:只要最右侧的NOTES列存在内容,整个已使用范围就会延伸到NOTES列,中间的空白列既不会截断这个矩形范围,row.Cells()迭代时也不会因为遇到空白单元格就终止,完全达不到跳过最后一列的效果。
靠固定列数跳过最后一列的方案可维护性差,后续新增Papayas、Melons等水果列时总列数变化,就会出现逻辑错误。
实现方案
动态获取当前工作表已使用范围的最右列序号(即NOTES列的位置),遍历单元格时直接通过列号判断,跳过第一列和最后一列即可,不需要依赖固定列数,也不需要插入空白列。
核心逻辑:
- 工作表已使用范围的最右列永远是最右侧的
NOTES列,该值会随表格列数增减自动更新,无需硬编码 - 遍历行内单元格时,列号为1(首列门店名)、列号等于最右列序号(NOTES列)的单元格直接跳过,其余单元格做数值解析
- 替换原有
Int32.Parse+异常捕获的逻辑,用ClosedXML内置的TryGetValue<int>做类型判断,避免无意义的异常性能开销
修正后的代码如下:
using ClosedXML.Excel; ... var workbook = new XLWorkbook(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); var ws1 = workbook.Worksheet("SHEET A"); var usedRange = ws1.RangeUsed(); // 动态获取已使用范围最右列,即NOTES列的列号 int lastColumnIndex = usedRange.LastColumn().ColumnNumber(); var rows = usedRange.RowsUsed(); foreach (var row in rows) { foreach (IXLCell cell in row.Cells()) { int currentCol = cell.Address.ColumnNumber; // 跳过首列门店名、末列备注 if (currentCol == 1 || currentCol == lastColumnIndex) { continue; } // 直接尝试读取整数,无需依赖异常捕获判断格式 if (cell.TryGetValue(out int saleValue)) { Console.WriteLine(saleValue); } else { Console.WriteLine($"单元格{cell.Address}格式非法,当前值:{cell.Value}"); } } }
适配说明
- 完全支持动态新增数值列:不管中间新增多少水果销量列,只要
NOTES列始终在表格最右侧,逻辑就可以正常运行,不需要修改代码 - 即使个别行的
NOTES单元格为空,只要其他行的NOTES列有内容,最右列的计算就不会出错 - 如果后续需要调整表格结构,只要保证备注列在所有数值列的最右侧即可,不需要调整遍历逻辑
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

