web-dev-qa-db-fra.com

Lire CSV pour lister les objets

J'ai un fichier CSV avec une liste de données variées (datetime, décimal). Exemple de ligne de CSV:

Date,Open,High,Low,Close,Volume,Adj Close  //I need to skip this first line as well
2012-11-01,77.60,78.12,77.37,78.05,186200,78.05

J'ai créé une liste d'objets dans lesquels je veux lire chacune des lignes. Le constructeur des objets est ci-dessous, chacun des champs de chaque ligne CSV est utilisé et attribué ici.

    public DailyValues(DateTime date, decimal open, decimal high, decimal low,
        decimal close, decimal volume, decimal adjClose)
        : this()
    {
        Date = date;
        Open = open;
        High = high;
        Low = low;
        Close = close;
        Volume = volume;
        AdjClose = adjClose;
    }

    List<DailyValues> values = new List<DailyValues>();

Existe-t-il un moyen facile de lire chaque ligne du CSV dans ma liste values et d'affecter de manière appropriée chaque attribut (c'est-à-dire la date, ouvert, élevé)?

26
user3066571

Pourquoi ne pas simplement les analyser explicitement? Vous avez un nombre limité de propriétés, donc ce n'est pas très difficile. Au lieu d'utiliser un constructeur nécessitant de nombreux arguments, j'ai utilisé une méthode statique qui retourne une nouvelle instance DailyValues comme son type de retour. Ceci est similaire à DateTime.FromBinary Etc.

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

namespace CsvDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            List<DailyValues> values = File.ReadAllLines("C:\\Users\\Josh\\Sample.csv")
                                           .Skip(1)
                                           .Select(v => DailyValues.FromCsv(v))
                                           .ToList();
        }
    }

    class DailyValues
    {
        DateTime Date;
        decimal Open;
        decimal High;
        decimal Low;
        decimal Close;
        decimal Volume;
        decimal AdjClose;

        public static DailyValues FromCsv(string csvLine)
        {
            string[] values = csvLine.Split(',');
            DailyValues dailyValues = new DailyValues();
            dailyValues.Date = Convert.ToDateTime(values[0]);
            dailyValues.Open = Convert.ToDecimal(values[1]);
            dailyValues.High = Convert.ToDecimal(values[2]);
            dailyValues.Low = Convert.ToDecimal(values[3]);
            dailyValues.Close = Convert.ToDecimal(values[4]);
            dailyValues.Volume = Convert.ToDecimal(values[5]);
            dailyValues.AdjClose = Convert.ToDecimal(values[6]);
            return dailyValues;
        }
    }
}

Bien sûr, vous pouvez toujours ajouter un constructeur par défaut et vous souhaiterez ajouter la gestion des exceptions en cas d'échec de l'analyse (vous pouvez également utiliser TryParse pour cela).

  • Le File.ReadAllLines Lit toutes les lignes du fichier CSV dans un tableau de chaînes.
  • La .Skip(1) saute la ligne d'en-tête.
  • La fonction .Select(v => DailyValues.FromCsv(v)) utilise Linq pour sélectionner chaque ligne et créer une nouvelle instance DailyValues à l'aide de la méthode FromCsv. Cela crée un type System.Collections.Generic.IEnumerable<CsvDemo.DailyValues>.
  • Enfin, la .ToList() convertit le IEnumerable en List pour correspondre au type souhaité.

Au lieu d'utiliser Linq, vous auriez pu simplement utiliser une boucle foreach pour ajouter chaque instance DailyValues à votre liste.

71
grovesNL