将CSV数据导入C#类

s4n0splo  于 2023-09-27  发布在  C#
关注(0)|答案(7)|浏览(111)

我知道如何读取和显示一行.csv文件。现在,我想解析该文件,将其内容存储在数组中,并将这些数组用作我创建的一些类的值。
不过我想学一下。
下面是一个示例:

basketball,2011/01/28,Rockets,Blazers,98,99
baseball,2011/08/22,Yankees,Redsox,4,3

如您所见,每个字段都用逗号分隔。我已经创建了Basketball.cs和Baseball类,它们是Sport.cs类的扩展,具有以下字段:

private string sport;
private string date;
private string team1;
private string team2;
private string score;

我知道这是简单化的,有更好的方法来存储这些信息,即。为每个团队创建类,使日期成为DateType数据类型,以及更多相同的内容,但我想知道如何将这些信息输入到类中。
我假设这与getter和setter有关...我也读过字典和集合,但我想先简单地把它们都存储在数组中。(如果这是有意义的……)请随意纠正我)。
以下是我目前所掌握的。它所做的就是读取csv并在控制台上鹦鹉学舌地说出其内容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Assign01
{
    class Program
    {
        static void Main(string[] args)
        {
            string line;
            FileStream aFile = new FileStream("../../sportsResults.csv", FileMode.Open);
            StreamReader sr = new StreamReader(aFile);

            // read data in line by line
            while ((line = sr.ReadLine()) != null)
            {
                Console.WriteLine(line);
                line = sr.ReadLine();
            }
            sr.Close();
        }
    }
}

我们将不胜感激。

dluptydi

dluptydi1#

对于弹性、快速和低工作量的解决方案,您可以使用CsvHelper,它可以处理大量代码和边缘情况,并且具有非常好的documentation

首先安装CsvHelper package on Nuget

dotnet add package CsvHelper

a)CSV with Headers(Demo in DotNet Fiddle

如果你的csv有这样的头:

sport,date,team 1,team 2,score 1,score 2
basketball,2011/01/28,Rockets,Blazers,98,99
baseball,2011/08/22,Yankees,Redsox,4,3

您可以向类添加属性,以将字段名称Map到类名,如下所示:

public class SportStats
{
    [Name("sport")]
    public string Sport { get; set; }
    [Name("date")]
    public DateTime Date { get; set; }
    [Name("team 1")]
    public string TeamOne { get; set; }
    [Name("team 2")]
    public string TeamTwo { get; set; }
    [Name("score 1")]
    public int ScoreOne { get; set; }
    [Name("score 2")]
    public int ScoreTwo { get; set; }
}

然后像这样调用:

using var sr = new StreamReader(@".\stats.csv");
using var csv = new CsvReader(sr, CultureInfo.InvariantCulture);

var records = csv.GetRecords<SportStats>().ToList();

B)CSV * 不带 * 头(Demo in DotNet Fiddle

如果你的csv没有这样的头:

basketball,2011/01/28,Rockets,Blazers,98,99
baseball,2011/08/22,Yankees,Redsox,4,3

你可以添加属性到你的类中,并按位置顺序Map到CSV,如下所示:

public class SportStats
{
    [Index(0)]
    public string Sport { get; set; }
    [Index(1)]
    public DateTime Date { get; set; }
    [Index(2)]
    public string TeamOne { get; set; }
    [Index(3)]
    public string TeamTwo { get; set; }
    [Index(4)]
    public int ScoreOne { get; set; }
    [Index(5)]
    public int ScoreTwo { get; set; }
}

然后像这样调用:

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    HasHeaderRecord = false,
};

using var sr = new StreamReader(@".\stats.csv");
using var csv = new CsvReader(sr, config);

var records = csv.GetRecords<SportStats>().ToList();

延伸阅读

gwo2fgha

gwo2fgha2#

创建数组来保存信息不是一个好主意,因为你不知道输入文件中有多少行。您的阵列的初始大小是多少??我建议您使用通用列表来保存信息(例如:列表<>)。
你也可以添加一个构造函数到你的Sport类,它接受一个数组(如上面的答案所述的拆分操作的结果)。
此外,您可以在setter中提供一些转换

public class Sport
{
    private string sport;
    private DateTime date;
    private string team1;
    private string team2;
    private string score;

    public Sport(string[] csvArray)
    {
        this.sport = csvArray[0];
        this.team1 = csvArray[2];
        this.team2 = csvArray[3];
        this.date = Convert.ToDateTime(csvArray[1]);
        this.score = String.Format("{0}-{1}", csvArray[4], csvArray[5]);
    }

为了简单起见,我编写了Convert方法,但请记住,这也不是一种非常安全的方法,除非您确定DateField始终包含有效的日期,并且Score始终包含数值。您可以尝试其他更安全的方法,如tryParse或一些异常处理。
我所有的诚实,它必须补充说,上述解决方案是简单的(如要求),在概念层面上,我会反对它。将属性和csv文件之间的Map逻辑放在类中会使sports类过于依赖文件本身,从而降低可重用性。文件结构中的任何后续更改都应该反映在您的类中,并且通常可以忽略。因此,明智的做法是将“Map&转换”逻辑放在主程序中,并尽可能保持类的整洁
(Changed your "Score" issue by formatting it as 2 strings combined with a hyphen)

xiozqbni

xiozqbni3#

将sting分割成数组以获得数据可能容易出错并且速度慢。尝试使用OLE数据提供程序读取CSV,就像它是SQL数据库中的表一样,这样就可以使用WHERE子句筛选结果。

应用配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="csv" providerName="System.Data.OleDb" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source='C:\CsvFolder\';Extended Properties='text;HDR=Yes;FMT=Delimited';" />
  </connectionStrings>
</configuration>

program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Configuration;
using System.Data;
using System.Data.Common;

namespace CsvImport
{
    class Stat
    {
        public string Sport { get; set; }
        public DateTime Date { get; set; }
        public string TeamOne { get; set; }
        public string TeamTwo { get; set; }
        public int Score { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ConnectionStringSettings csv = ConfigurationManager.ConnectionStrings["csv"];
            List<Stat> stats = new List<Stat>();

            using (OleDbConnection cn = new OleDbConnection(csv.ConnectionString))
            {
                cn.Open();
                using (OleDbCommand cmd = cn.CreateCommand())
                {
                    cmd.CommandText = "SELECT * FROM [Stats.csv]";
                    cmd.CommandType = CommandType.Text;
                    using (OleDbDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
                    {
                        int fieldSport = reader.GetOrdinal("sport");
                        int fieldDate = reader.GetOrdinal("date");
                        int fieldTeamOne = reader.GetOrdinal("teamone");
                        int fieldTeamTwo = reader.GetOrdinal("teamtwo");
                        int fieldScore = reader.GetOrdinal("score");

                        foreach (DbDataRecord record in reader)
                        {
                            stats.Add(new Stat
                            {
                                Sport = record.GetString(fieldSport),
                                Date = record.GetDateTime(fieldDate),
                                TeamOne = record.GetString(fieldTeamOne),
                                TeamTwo = record.GetString(fieldTeamTwo),
                                Score = record.GetInt32(fieldScore)
                            });
                        }
                    }
                }
            }

            foreach (Stat stat in stats)
            {
                Console.WriteLine("Sport: {0}", stat.Sport);
            }
        }
    }
}

下面是csv的外观

stats.csv

sport,date,teamone,teamtwo,score
basketball,28/01/2011,Rockets,Blazers,98
baseball,22/08/2011,Yankees,Redsox,4
igsr9ssn

igsr9ssn4#

Linq也有一个解决方案,您可以将输出定义为List或Array。在下面的例子中,有一个类作为数据和数据类型的定义。

var modelData = File.ReadAllLines(dataFile)
                   .Skip(1)
                   .Select(x => x.Split(','))
                   .Select(dataRow => new TestModel
                   {
                       Column1 = dataRow[0],
                       Column2 = dataRow[1],
                       Column3 = dataRow[2],
                       Column4 = dataRow[3]
                   }).ToList(); // Or you can use .ToArray()
mnemlml8

mnemlml85#

虽然有很多库可以使CSV阅读变得容易(请参阅:here),现在你所需要做的就是分割它。

String[] csvFields = line.Split(",");

现在将每个字段分配给适当的成员

sport = csvFields[0];
date = csvFields[1];
//and so on

但是,每次读取新行时,这将覆盖值,因此您需要将值打包到类中,并将该类的示例保存到列表中。

vxqlmq5t

vxqlmq5t6#

// use "Microsoft.VisualBasic.dll"

using System;
using Microsoft.VisualBasic.FileIO;

class Program {
    static void Main(string[] args){
        using(var csvReader = new TextFieldParser(@"sportsResults.csv")){
            csvReader.SetDelimiters(new string[] {","});
            string [] fields;
            while(!csvReader.EndOfData){
                fields = csvReader.ReadFields();
                Console.WriteLine(String.Join(",",fields));//replace make instance
            }
        }
    }
}
x7yiwoj4

x7yiwoj47#

下面是为新手和吸引眼球的解决方案,大多数新手喜欢尝试和错误,请唐; t forget to add System.Core.dll in references在.cs文件中导入命名空间:使用System.Linq;
也许添加迭代器会是更好的代码

private static IEnumerable<String> GetDataPerLines()
{
    FileStream aFile = new FileStream("sportsResults.csv",FileMode.Open);             
    StreamReader sr = new StreamReader(aFile); 
    while ((line = sr.ReadLine()) != null)             
    { 
        yield return line;
    }             
    sr.Close(); 
}

static void Main(string[] args)
{
    var query = from data in GetDataPerLines()
          let splitChr = data.Split(",".ToCharArray())
                select new Sport
    {
       sport = splitChr[0],
       date = splitChr[1],.. and so on
    }

    foreach (var item in query)
    {
        Console.Writeline(" Sport = {0}, in date when {1}",item.sport,item.date);
    }
}

也许像这样,上面的示例使用yield创建自己的迭代(请查看MSDN文档)并基于字符串创建集合。
让我知道如果我写错了代码,因为我不;我写答案的时候没有Visual Studio。据您所知,像“Sport[]”这样的一维数组将转换为CLR IEnumerable

相关问题