如何读取 excel 文件,其中列在一行中重复并将它们转换为数据表

How to read an excel file where columns are repeated in a single row and convert them into datatable

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

我的 table 看起来像这样:

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

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

但是我的Excelsheet是这样填的:

日期是 Day,Score 和 CutOf 在单列中 header,并且它们在单行中重复。

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

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!";
        }

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

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; }
    }
}

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