You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何使用ClosedXML将Excel工作表读取至C# DataTable?

使用ClosedXML将Excel读取到C# DataTable的实现方案

没问题!用ClosedXML来搞定这个需求刚好合适,完全不需要依赖Microsoft.ACE.OLEDB驱动,完美解决你遇到的环境问题。下面是具体的实现步骤和代码:

第一步:安装ClosedXML

首先通过NuGet安装ClosedXML包,你可以在Visual Studio的NuGet包管理器中搜索ClosedXML并安装,或者在包管理器控制台执行命令:

Install-Package ClosedXML

第二步:核心实现代码

下面的方法可以处理列数行数不固定的Excel表,首行作为列名,同时自动过滤完全空白的数据行(如果需要保留全空行,去掉对应的判断即可):

using ClosedXML.Excel;
using System.Data;
using System.Linq;

public class ExcelReader
{
    public DataTable ReadExcelToDataTable(string filePath, string sheetName = null)
    {
        var resultTable = new DataTable();
        
        // 打开Excel文件,using自动释放资源
        using (var workbook = new XLWorkbook(filePath))
        {
            // 选择目标工作表:指定名称则用指定的,否则取第一个工作表
            var targetSheet = string.IsNullOrEmpty(sheetName) 
                ? workbook.Worksheets.First() 
                : workbook.Worksheet(sheetName);
            
            // 读取首行作为DataTable的列名
            var headerRow = targetSheet.Row(1);
            int totalColumns = headerRow.CellsUsed().Count();
            
            // 逐个添加列到DataTable
            foreach (var headerCell in headerRow.CellsUsed())
            {
                // 处理空列名:如果首行单元格为空,自动生成列名(比如Column1、Column2)
                string columnName = string.IsNullOrWhiteSpace(headerCell.Value.ToString())
                    ? $"Column{headerCell.ColumnNumber}"
                    : headerCell.Value.ToString();
                
                // 避免列名重复(如果有相同列名,自动加后缀)
                if (resultTable.Columns.Contains(columnName))
                {
                    columnName = $"{columnName}_{headerCell.ColumnNumber}";
                }
                
                resultTable.Columns.Add(columnName);
            }
            
            // 遍历数据行(从第二行开始,跳过首行列名)
            foreach (var dataRow in targetSheet.RowsUsed().Skip(1))
            {
                var newDataRow = resultTable.NewRow();
                bool isRowAllEmpty = true;
                
                // 逐个单元格读取值
                for (int colIndex = 0; colIndex < totalColumns; colIndex++)
                {
                    var cell = dataRow.Cell(colIndex + 1); // ClosedXML的列索引从1开始
                    string cellValue = cell.Value.ToString();
                    
                    // 空单元格用DBNull.Value填充,避免DataTable报错
                    newDataRow[colIndex] = string.IsNullOrWhiteSpace(cellValue) ? DBNull.Value : cellValue;
                    
                    // 标记此行是否有非空值
                    if (!string.IsNullOrWhiteSpace(cellValue))
                    {
                        isRowAllEmpty = false;
                    }
                }
                
                // 仅添加非全空的行到DataTable(如果需要保留全空行,删除这个判断即可)
                if (!isRowAllEmpty)
                {
                    resultTable.Rows.Add(newDataRow);
                }
            }
        }
        
        return resultTable;
    }
}

关键细节说明

  • CellsUsed()RowsUsed():这两个方法会自动跳过完全空白的单元格/行,提升读取效率,同时避免处理不必要的空内容。
  • 空列名处理:如果首行有空白单元格,会自动生成类似ColumnX的列名,同时处理重复列名的情况,避免DataTable抛出异常。
  • 空值处理:空白单元格用DBNull.Value填充,符合DataTable的空值规范。
  • 格式支持:ClosedXML仅支持.xlsx格式的Excel文件,如果需要处理旧版.xls文件,可能需要额外的转换工具或库。

使用示例

调用方法很简单,比如读取指定路径的第一个工作表:

var reader = new ExcelReader();
DataTable excelData = reader.ReadExcelToDataTable(@"C:\YourFile.xlsx");

如果要指定工作表名:

DataTable excelData = reader.ReadExcelToDataTable(@"C:\YourFile.xlsx", "Sheet2");

内容的提问来源于stack exchange,提问作者webworm

火山引擎 最新活动