【问题标题】:How to convert an Excel file to .CSV using ClosedXML for un-structured data如何使用 ClosedXML 将 Excel 文件转换为 .CSV 以获取非结构化数据
【发布时间】:2021-12-09 00:10:25
【问题描述】:

我有一个场景,我需要在 Net core 3.1 应用程序中将 MS Excel 文件转换为 .CSV 格式。 Excel文件中的数据不是表格格式,有些地方合并了单元格或者一些表头信息,然后是表格数据。

我尝试使用 ClosedXMl 读取该数据并将其放入 DataTable 中,但它的处理方式有所不同,因为最初的几行与导致修剪几列的其余数据不一致。

我的 Excel 看起来像

这里,前 2 行仅跨越 3 列。

以下是我使用 closedXML 的代码。

public static DataTable GetData(string filename)
        {
            DataTable dt = new DataTable();
            //Open the Excel file using ClosedXML.
            using (XLWorkbook workBook = new XLWorkbook(filename))
            {
                //Read the first Sheet from Excel file.
                IXLWorksheet workSheet = workBook.Worksheet(1);
                //Create a new DataTable.

                //Loop through the Worksheet rows.
                int rowsToSkip = 1;
                foreach (IXLRow row in workSheet.Rows())
                {

                    var cellsCount = row.Cells().Count();

                    ////Use the first row to add columns to DataTable.
                    if (rowsToSkip <= 3)
                    {
                        foreach (IXLCell cell in row.Cells())
                        {
                            if (!string.IsNullOrEmpty(cell.Value.ToString()))
                            {
                                dt.Columns.Add(cell.Value.ToString());
                            }
                            else
                            {
                                break;
                            }
                        }                       
                    }
                    else
                    {
                        int i = 0;
                        DataRow toInsert = dt.NewRow();
                        foreach (IXLCell cell in row.Cells())
                        {
                            try
                            {
                                toInsert[i] =Convert.ToString(cell.Value);
                            }
                            catch (Exception ex)
                            {
                                //Handle this, or don't.
                            }
                            i++;
                        }
                        dt.Rows.Add(toInsert);
                    }
                    rowsToSkip++;
                }


                return dt;
            }
        }



        public static void ToCSV(DataTable dtDataTable, string strFilePath)
        {
            StreamWriter sw = new StreamWriter(strFilePath, false);
            //headers    
            for (int i = 0; i < dtDataTable.Columns.Count; i++)
            {
                sw.Write(dtDataTable.Columns[i]);
                if (i < dtDataTable.Columns.Count - 1)
                {
                    sw.Write(",");
                }
            }
            sw.Write(sw.NewLine);
            foreach (DataRow dr in dtDataTable.Rows)
            {
                for (int i = 0; i < dtDataTable.Columns.Count; i++)
                {
                    if (!Convert.IsDBNull(dr[i]))
                    {
                        string value = dr[i].ToString();
                        if (value.Contains(','))
                        {
                            value = String.Format("\"{0}\"", value);
                            sw.Write(value);
                        }
                        else
                        {
                            sw.Write(dr[i].ToString());
                        }
                    }
                    if (i < dtDataTable.Columns.Count - 1)
                    {
                        sw.Write(",");
                    }
                }
                sw.Write(sw.NewLine);
            }
            sw.Close();
        }

在 GetData() 中,它只在数据表中创建 3 列,因为初始行仅跨越 3 列。

当我可以将非结构化数据放入数据表并写入 CSV 时,我非常感谢处理这种情况的任何输入。我也对 EPPlus 4.5 或类似的其他开源软件包持开放态度。

【问题讨论】:

    标签: c# excel .net-core epplus closedxml


    【解决方案1】:

    我知道这是一个月前的问题,希望您仍然需要答案。

    首先,对于您的 closedxml 代码,我注意到它是已接受答案 here 的略微修改版本。只想快速说接受的答案不是最好的,因为如果电子表格底部有空白行,它会引发空引用异常。很少发生,但仍然会发生。因此,我将在同一个问题上使用未接受答案的修改版本。

    您的代码没有添加正确的标题,因为您正在为第 1-3 行添加列,原因如下: if (rowsToSkip &lt;= 3)

    我创建了以下电子表格:

    使用此方法,可以正确导入。

        public static DataTable ImportExcel(string path)
        {
            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(1);
    
                //Loop through the Worksheet rows.
                bool addRows = false;
                int rowCount = 1;
                foreach (IXLRow row in workSheet.Rows())
                {
                    //If we're on row 3, add headers and toggle flag to addRows.
                    if (rowCount == 3)
                    {
                        foreach (IXLCell cell in row.Cells())
                        {
                            if (!string.IsNullOrEmpty(cell.Value.ToString()))
                            {
                                dt.Columns.Add(cell.Value.ToString());
                            }
                            else
                            {
                                break;
                            }
                        }
                        addRows = true;
                    }
                    else if (addRows)
                    {
                        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)
                            {
                                //Handle this.
                                //Log it or throw
                            }
                            i++;
                        }
                        dt.Rows.Add(toInsert);
                    }
                    rowCount++;
                }
                return dt;
            }
        }
    

    我使用了您的 CSV 代码,但我建议将来使用 CSVHelper 之类的代码,以帮助解决将来可能出现的任何未知数。

    输出文件:

    【讨论】:

      猜你喜欢
      • 2016-02-16
      • 2017-11-26
      • 1970-01-01
      • 2015-01-05
      • 2020-05-15
      • 1970-01-01
      • 2022-11-22
      • 1970-01-01
      • 2019-09-16
      相关资源
      最近更新 更多