【问题标题】:Read Excel worksheet into DataTable using ClosedXML使用 ClosedXML 将 Excel 工作表读入 DataTable
【发布时间】:2018-07-23 05:04:58
【问题描述】:

我想将 Excel 工作表的内容读入 C# DataTable。 Excel 工作表可以有可变数量的列和行。 Excel 工作表中的第一行将始终包含列名,但其他行可能为空白。

我在 SO 中看到的所有建议都假设存在 Microsoft.ACE.OLEDB。我的系统上没有安装这个库,因为当我尝试其中一些解决方案时,我得到了这个错误。

Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.

奇怪的是我安装了 Office 2016。

出于这个原因,我希望通过 Nuget 使用 ClosedXML 库,但我在他们的 wiki 中没有看到任何将 Excel 工作表读取到 C# 中的 DataTable 的示例。

【问题讨论】:

    标签: excel datatable closedxml


    【解决方案1】:

    这个例子不是我的。我不记得我从哪里得到它,因为它在我的档案中。但是,这对我有用。我遇到的唯一问题是空白单元格。根据dicussion on the ClosedXML GitHUb wiki page,它与 Excel 不跟踪不受数据限制的空单元格有关。我发现,如果我将数据添加到单元格中,然后删除相同的数据,则该过程会起作用。

    public static DataTable ImportExceltoDatatable(string filePath, string sheetName)
    {
      // Open the Excel file using ClosedXML.
      // Keep in mind the Excel file cannot be open when trying to read it
      using (XLWorkbook workBook = new XLWorkbook(filePath))
      {
        //Read the first Sheet from Excel file.
        IXLWorksheet workSheet = workBook.Worksheet(1);
    
        //Create a new DataTable.
        DataTable dt = new DataTable();
    
        //Loop through the Worksheet rows.
        bool firstRow = true;
        foreach (IXLRow row in workSheet.Rows())
        {
          //Use the first row to add columns to DataTable.
          if (firstRow)
          {
            foreach (IXLCell cell in row.Cells())
            {
              dt.Columns.Add(cell.Value.ToString());
            }
            firstRow = false;
          }
          else
          {
            //Add rows to DataTable.
            dt.Rows.Add();
            int i = 0;
    
            foreach (IXLCell cell in row.Cells(row.FirstCellUsed().Address.ColumnNumber, row.LastCellUsed().Address.ColumnNumber))
            {
              dt.Rows[dt.Rows.Count - 1][i] = cell.Value.ToString();
              i++;
            }
          }
        }
    
        return dt;
      }
    }
    

    需要补充

    using System.Data;
    using ClosedXML.Excel;
    

    以及 ClosedXML nuget 包

    对于其他日期时间数据类型...这可能会有所帮助...reference

    if (cell.Address.ColumnLetter=="J") // Column with date datatype
     {
        DateTime dtime = DateTime.FromOADate(double.Parse(cell.Value.ToString()));
                         dt.Rows[dt.Rows.Count - 1][i] = dtime;
     }
     else
     {
          dt.Rows[dt.Rows.Count - 1][i] = cell.Value.ToString();
     }
    

    【讨论】:

    • 我们如何处理日期数据类型?
    • @singhswat 我将所有内容都视为字符串
    • 在这一行抛出空引用异常。 foreach (行中的 IXLCell 单元格.Cells(row.FirstCellUsed().Address.ColumnNumber, row.LastCellUsed().Address.ColumnNumber))
    • @JyotirmayaPrusty 将包含 for 循环的 else 条件的内容包装在条件“if(row.FirstCellUsed() != null)”中。否则,它会在一个完全空的行上失败。
    • 如果您的工作表包含公式“值”将崩溃。在我看来,尽管在我测试的所有情况下,使用“CachedValue”都能得到你想要的东西。这也适用于直接值,因为两者包含相同的值。 “InnerText”可能是另一种选择。
    【解决方案2】:

    使用此代码,您可以读取 Excel 工作表的内容。您可以指定工作表的名称或编号,将返回一个数据集,其中包含工作表的内容。

    public static DataTable GetDataFromExcel(string path, dynamic worksheet)
            {
                //Save the uploaded Excel file.
    
    
                DataTable dt = new DataTable();
                //Open the Excel file using ClosedXML.
                using (XLWorkbook workBook = new XLWorkbook(path))
                {
                    //Read the first Sheet from Excel file.
                    IXLWorksheet workSheet = workBook.Worksheet(worksheet);
    
                    //Create a new DataTable.
    
                    //Loop through the Worksheet rows.
                    bool firstRow = true;
                    foreach (IXLRow row in workSheet.Rows())
                    {
                        //Use the first row to add columns to DataTable.
                        if (firstRow)
                        {
                            foreach (IXLCell cell in row.Cells())
                            {
                                if (!string.IsNullOrEmpty(cell.Value.ToString()))
                                {
                                    dt.Columns.Add(cell.Value.ToString());
                                }
                                else
                                {
                                    break;
                                }
                            }
                            firstRow = false;
                        }
                        else
                        {
                            int i = 0;
                            DataRow toInsert = dt.NewRow();
                            foreach (IXLCell cell in row.Cells(1, dt.Columns.Count))
                            {
                                try
                                {
                                    toInsert[i] = cell.Value.ToString();
                                }
                                catch (Exception ex)
                                {
    
                                }
                                i++;
                            }
                            dt.Rows.Add(toInsert);
                        }
                    }
                    return dt;
                }
    

    【讨论】:

    • 这应该是公认的答案。它按预期工作。
    猜你喜欢
    • 2018-01-13
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 2020-10-12
    • 2018-04-13
    • 2012-05-19
    相关资源
    最近更新 更多