Citire CSV pentru lista de obiecte [duplicat] (Programare, C#, Csv)

user3066571 a intrebat.

Am un fișier CSV cu o listă de date variate(datetime, zecimale). Exemplu de linie din 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

Am creat o listă de obiecte în care vreau să citesc fiecare dintre linii. Constructorul pentru obiecte este mai jos, fiecare dintre câmpurile din fiecare linie CSV este folosit și atribuit aici.

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

Există o modalitate ușoară de a citi fiecare linie din CSV în lista mea values și să atribui în mod corespunzător fiecare atribut (adică data, open, high)?

Comentarii

  • Există un TextFieldParser clasă ascunsă în Microsoft.VisualBasic.FileIO în spațiul de nume. Chiar dacă scrie VisualBasic, o puteți folosi și cu C#. –  > Por cost.
  • Eu aș face acest lucru prin Linq – vezi această postare: stackoverflow.com/questions/3497699/csv-to-object-model-mapping –  > Por Kevin.
  • @Kevin Asta nu este în totalitate conform cu specificația CSV. Ar exista probleme dacă ar exista date care conțin o virgulă în cadrul datelor –  > Por cost.
  • @cost – Sunt complet de acord, dar uitându-mă la datele de exemplu nu văd nicio problemă. –  > Por Kevin.
1 răspunsuri
grovesNL

De ce să nu le analizați în mod explicit? Aveți un număr limitat de proprietăți, deci nu este foarte dificil. În loc să folosesc un constructor care necesită multe argumente, am folosit o metodă statică care returnează un nou DailyValues instanță ca tip de returnare. Acest lucru este similar cu 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;
        }
    }
}

Bineînțeles, puteți adăuga în continuare un constructor implicit și veți dori să adăugați gestionarea excepțiilor în cazul în care analizarea nu reușește (puteți utiliza și TryParse pentru acest lucru).

  • Site-ul File.ReadAllLines citește toate liniile din fișierul CSV într-un array de șiruri.
  • Adresa .Skip(1) sare peste linia de antet.
  • .Select(v => DailyValues.FromCsv(v)) utilizează Linq pentru a selecta fiecare linie și a crea un nou fișier DailyValues instanță folosind FromCsv metoda . Astfel, se creează un fișier System.Collections.Generic.IEnumerable<CsvDemo.DailyValues> tip.
  • În cele din urmă, metoda .ToList() convertește IEnumerable la un List pentru a se potrivi cu tipul pe care îl doriți.

În loc să folosiți Linq, ați fi putut folosi pur și simplu un foreach buclă pentru a adăuga fiecare DailyValues instanță la listă.

Comentarii

  • Îmi place această abordare și, dacă este necesar, ați putea implementa o analiză CSV mai complexă în FromCsv. +1 –  > Por Kevin.
  • Aceasta este mult mai simplă decât orice altă soluție oferită pe stackoverflow 🙂 –  > Por Un muncitor inteligent.
  • Simplu și eficient ! +1 –  > Por anil.
  • Nu este în defect, deși, ce se întâmplă dacă a existat o virgulă în datele reale, de exemplu, „Los Angeles, CA” s-ar împărți în 2 câmpuri separate. Este în regulă dacă știi că datele nu conțin șiruri de caractere. –  > Por Paul.
  • @Paul: Categoric, dar majoritatea implementărilor au standarde diferite pentru a gestiona scăparea virgulelor/caracterelor speciale (de exemplu, o modalitate este de a înfășura valorile care conțin virgule în ghilimele duble, așa cum ați spus). Deci, probabil că ar fi mai bine să modificați logica pentru aceste cazuri, atunci când sunt cunoscute, sau să folosiți în schimb o bibliotecă care se ocupă de parsarea CSV. Răspunsul meu presupune cel mai simplu caz, așa cum este descris în întrebare. –  > Por grovesNL.

Tags:,