【问题标题】:How to read an excel file where columns are repeated in a single row and convert them into datatable如何读取列在单行中重复的excel文件并将它们转换为数据表
【发布时间】:2021-10-05 19:17:44
【问题描述】:

我需要导入一个 Excel 表格并读取数据并将此数据添加到 ASP.NET Core MVC 中的数据库中。

我的桌子是这样的:

当我有 excel 这种格式的数据时:

我能够读取数据并将其添加到数据库中。

但我的 Excel 表格是这样填写的:

其中日期是 Day,Score 和 CutOf 位于单列标题中,并且这些在单行中重复。

那么如何读取并将它们转换为每个人的行基础并将它们添加到数据库中?

var dt = new DataTable();

//Checking file content length and Extension must be .xlsx
if (file != null && file.ContentType.Length > 0 && System.IO.Path.GetExtension(file.FileName).ToLower() == ".xlsx")
{
    //Create a Folder.
    string path = Path.Combine(hostingEnv.WebRootPath, "Uploads");
    
    if (!Directory.Exists(path))
    {
        Directory.CreateDirectory(path);
    }
    
    //Save the uploaded Excel file.
    string fileName = Path.GetFileName(file.FileName);
    string filePath = Path.Combine(path, fileName);

    using (var stream = new FileStream(filePath, FileMode.Create))
    {
        file.CopyTo(stream);
    }
    
    using (var workbook = new XLWorkbook(filePath))
    {
        IXLWorksheet worksheet = workbook.Worksheet(1);
        bool FirstRow = true;

        //Range for reading the cells based on the last cell used.
        string readRange = "1:1";
        
        foreach (IXLRow row in worksheet.RowsUsed())
        {
            //If Reading the First Row (used) then add them as column name
            if (FirstRow)
            {
                //Checking the Last cellused for column generation in datatable
                readRange = string.Format("{0}:{1}", 1, row.LastCellUsed().Address.ColumnNumber);
                
                foreach (IXLCell cell in row.Cells(readRange))
                {
                    dt.Columns.Add(cell.Value.ToString());
                }
                
                FirstRow = false;
            }
            else
            {
                //Adding a Row in datatable
                dt.Rows.Add();
                int cellIndex = 0;
                
                //Updating the values of datatable
                foreach (IXLCell cell in row.Cells(readRange))
                {
                    dt.Rows[dt.Rows.Count - 1][cellIndex] = cell.Value.ToString();
                    cellIndex++;
                }
            }
        }
        
        //If no data in Excel file
        if (FirstRow)
        {
            ViewBag.Message = "Empty Excel File!";
        }

【问题讨论】:

  • 这与您在帖子中标记的所有网络技术有什么关系?您编写了哪些代码来尝试解决此问题? Stack Overflow 不是代码编写服务,因此您应该尝试自己实现它。如果你不能让它工作,展示你尝试过的东西并解释它是如何不工作的。
  • @mason 嘿,梅森,我有没有提到说给我密码?你不需要伤害别人,只是为了你访问的问题。我只被问到如何迭代重复的列,因为我不能在类对象中有那么多属性并分配它们
  • 您没有明确声明您希望有人给您代码。但是当时您还没有提供任何代码,因此这是您所寻求的合乎逻辑的结论。我不是来伤害你的——我是来帮忙的。这意味着帮助您了解该网站的最佳运作方式。我们已经制定了应该如何提出问题的标准——我们在过去十多年中制定的标准,以帮助您明确问题并获得答案。我看到您现在已将代码编辑到您的问题中,谢谢。
  • 您已经展示了 Excel 文件的外观。它总是会连续两天得分吗?或者可以有 1 到 N,或 0 到 N?还是1到7?还是 0 到 7?
  • 谢谢,梅森,从现在开始,我将在发布问题时保持标准。它将有1到N天以及excel中的分数。我的数据库表看起来像`ID |姓名 |分数 | Outof ` 在给定的 excel 表中,在单个列中,我有得分以及 OutOf (Score/20)。

标签: c# .net closedxml


【解决方案1】:

由于您拥有动态数量的列,因此实际上只需遍历列并获取值即可。我在我的机器上重新创建了这个。

using System;
using System.Collections.Generic;
using ClosedXML.Excel;

namespace HelloDotNetCore
{
    class Program
    {
        static void Main(string[] args)
        {
            var scoreResults = new List<ScoreResult>();

            using (var workbook = new XLWorkbook("Scores.xlsx"))
            {
                var isHeaderRow = true;

                foreach (var row in workbook.Worksheet(1).RowsUsed())
                {
                    if (isHeaderRow)
                    {
                        isHeaderRow = false;
                        continue;
                    }

                    var name = row.Cell(1).GetString();

                    // This goes through the Date, Score column pairs until the end is reached for that row
                    for (int i = 2; i <= row.LastCellUsed().Address.ColumnNumber; i+=2)
                    {
                        Console.WriteLine(row.Cell(i).GetString());

                        var scoreResult = new ScoreResult
                        {
                            Name = name,
                            DateTaken = row.Cell(i).GetDateTime(),
                            Score = row.Cell(i + 1).GetValue<int>(),
                        };

                        scoreResults.Add(scoreResult);
                    }
                }
            }

            foreach (var s in scoreResults)
            {
                Console.WriteLine($"Name: {s.Name}, DateTaken: {s.DateTaken}, Score: {s.Score}");
            }
        }
    }

    class ScoreResult
    {
        public string Name { get; set; }

        public DateTime DateTaken { get; set; }

        public int Score { get; set; }
    }
}

注意它如何获取分数并将它们存储在列表中以供以后使用?这比使用 DataTable 要好得多。

【讨论】:

  • 谢谢,梅森,是的,列表比你建议的要好得多,而不是 dataTable。以防万一有人想知道如何从标头中获取 OutOf 值。迭代第一行,将其存储在 List 和 for 循环中,索引将是相似的,因此获取值和 Score/17 值并将其拆分并将其分配给 OutOf。
猜你喜欢
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 2023-03-25
相关资源
最近更新 更多