Importing CSV data into C# classes

前端 未结 7 1340
广开言路
广开言路 2020-12-02 01:45

I know how to read and display a line of a .csv file. Now I would like to parse that file, store its contents in arrays, and use those arrays as values for some classes I cr

相关标签:
7条回答
  • 2020-12-02 02:21

    For a resilient, fast, and low effort solution, you can use CsvHelper which handles a lot of code and edge cases and has pretty good documentation

    First, install the CsvHelper package on Nuget

    a) CSV with Headers

    If your csv has headers like this:

    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
    

    You can add attributes to your class to map the field names to your class names like this:

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

    And then invoke like this:

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

    b) CSV without Headers

    If your csv doesn't have headers like this:

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

    You can add attributes to your class and map to the CSV ordinally by position like this:

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

    And then invoke like this:

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

    Further Reading

    • Reading CSV file and storing values into an array (295
    0 讨论(0)
  • 2020-12-02 02:25

    Linq also has a solution for this and you can define your output as either a List or an Array. In the example below there is a class that as the definition of the data and data types.

    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()
    
    0 讨论(0)
  • 2020-12-02 02:29

    Below is for newbie and eye catching solution that most newbie like to try and error please don;t forget to add System.Core.dll in references Import namespace in your .cs file : using System.Linq;

    Perhaps add iterator will be better code

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

    Maybe like this, the sample above is creating your own iteration using yield (please look at MSDN documentation for that) and create collection based on your string.

    Let me know if I write the code wrong since I don;t have Visual studio when I write the answer. For your knowledge, an array one dimension like "Sport[]" will translate into CLR IEnumerable

    0 讨论(0)
  • 2020-12-02 02:36
    // 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
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 02:37

    splitting the sting into arrays to get the data can be error prone and slow. Try using an OLE data provider to read the CSV as if it were a table in an SQL database, this way you can use a WHERE clause to filter the results.

    App.Config:

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

    Here's how the csv should look

    stats.csv:

    sport,date,teamone,teamtwo,score
    basketball,28/01/2011,Rockets,Blazers,98
    baseball,22/08/2011,Yankees,Redsox,4
    
    0 讨论(0)
  • 2020-12-02 02:40

    While there are a lot of libraries that will make csv reading easy (see: here), all you need to do right now that you have the line, is to split it.

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

    Now assign each field to the appropriate member

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

    This will however overwrite the values each time you read a new line, so you need to pack the values into a class and save the instances of that class to a list.

    0 讨论(0)
提交回复
热议问题