簡體   English   中英

將 CSV 數據導入 C# 類

[英]Importing CSV data into C# classes

我知道如何讀取和顯示 .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();
        }
    }
}

幫助將不勝感激。

對於一個有彈性、快速和省力的解決方案,您可以使用CsvHelper ,它處理大量代碼和邊緣情況,並有很好的文檔

首先,在Nuget 上安裝CsvHelper 包

CsvHelper nuget 下載

a)帶有標題的 CSV

如果您的 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

您可以向類添加屬性以將字段名稱映射到類名稱,如下所示:

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

然后像這樣調用:

List<SportStats> records;

using (var reader = new StreamReader(@".\stats.csv"))
using (var csv = new CsvReader(reader))
{
    records = csv.GetRecords<SportStats>().ToList();
}

b)沒有標題的 CSV

如果您的 csv 沒有這樣的標題:

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

您可以將屬性添加到您的類並按如下位置順序映射到 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; }
}

然后像這樣調用:

List<SportStats> records;

using (var reader = new StreamReader(@".\stats.csv"))
using (var csv = new CsvReader(reader))
{
    csv.Configuration.HasHeaderRecord = false;
    records = csv.GetRecords<SportStats>().ToList();
}

進一步閱讀

創建數組來保存信息不是一個好主意,因為您不知道輸入文件中有多少行。 你的 Array 的初始大小是多少? 我建議您使用例如通用列表來保留信息(例如列表<>)。

您還可以向接受數組的運動類添加一個構造函數(上述答案中描述的拆分操作的結果。

此外,您可以在 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 文件之間的映射邏輯放在類中會使運動類過於依賴文件本身,從而降低可重用性。 文件結構中的任何后續更改都應該反映在您的類中,並且通常會被忽略。 因此,將你的“映射和轉換”邏輯放在主程序中並盡可能保持你的類干凈是更明智的

將 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>

程序.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 的外觀

統計.csv

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

雖然有很多庫可以使 csv 讀取變得容易(請參閱: 此處),但您現在擁有該行所需要做的就是拆分它。

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

現在將每個字段分配給適當的成員

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

但是,每次讀取新行時,這都會覆蓋這些值,因此您需要將這些值打包到一個類中,並將該類的實例保存到一個列表中。

Linq 也有一個解決方案,您可以將輸出定義為列表或數組。 在下面的示例中,有一個類作為數據和數據類型的定義。

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()
// 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
            }
        }
    }
}

以下是大多數新手喜歡嘗試和錯誤的新手和引人注目的解決方案,請不要忘記在 .cs 文件中的引用導入命名空間中添加 System.Core.dll:使用 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM