Analisi dei file CSV in C #, con intestazione


266

Esiste un modo predefinito / ufficiale / consigliato per analizzare i file CSV in C #? Non voglio rotolare il mio parser.

Inoltre, ho visto casi di persone che usano ODBC / OLE DB per leggere CSV tramite il driver di testo, e molte persone lo scoraggiano a causa dei suoi "svantaggi". Quali sono questi svantaggi?

Idealmente, sto cercando un modo per leggere il CSV in base al nome della colonna, usando il primo record come nome di intestazione / campo. Alcune delle risposte fornite sono corrette ma funzionano sostanzialmente per deserializzare il file in classi.

Risposte:


138

Lascia che una libreria gestisca tutti i dettagli chiacchieroni per te! :-)

Dai un'occhiata a FileHelpers e resta ASCIUTTO - Non ripetere te stesso - non è necessario reinventare la ruota per un gazillionth time ....

Fondamentalmente devi solo definire quella forma dei tuoi dati - i campi nella tua linea individuale nel CSV - per mezzo di una classe pubblica (e attributi così ben ponderati come valori predefiniti, sostituzioni per valori NULL e così via), punto il motore FileHelpers in un file e il bingo: ottieni tutte le voci da quel file. Una semplice operazione: grandi prestazioni!


1
fino a quando non hai bisogno di qualcosa di veramente personalizzato (e la maggior parte di ciò può essere implementato comunque come estensioni) FileHelpers è di gran lunga il modo migliore per andare, soluzione davvero conveniente, testata e ben performante
mikus

3
A partire dal 1 ° giugno 2015, l'unico modo per scaricare FileHelpers era cercarlo su sourceforge.net. Ecco il link utilizzato: sourceforge.net/projects/filehelpers/?source=directory
Sudhanshu Mishra

2
@dotnetguy siamo in procinto di rilasciare la versione 3.1 (attualmente 3.1-rc2). Inoltre abbiamo ridisegnato il sito: www.filehelpers.net è possibile scaricare l'ultima versione da lì
Marcos Meli,

1
@MarcosMeli molte grazie! Ho già usato FileHelpers in uno dei miei progetti ed è stato un gioco da ragazzi - complimenti per il team. Sto pianificando presto un blog e tra l'altro - Adoro il nuovo sito - ben fatto!
Sudhanshu Mishra,

FileHelpers non gestisce correttamente le virgolette tra virgolette o effettivamente mappa le intestazioni dei campi, aspettandosi invece che le colonne siano nello stesso ordine in cui i campi sono dichiarati nel tuo tipo. Non lo userei, personalmente.
Alastair Maw,

358

Un parser CSV fa ora parte di .NET Framework.

Aggiungi un riferimento a Microsoft.VisualBasic.dll (funziona bene in C #, non importa il nome)

using (TextFieldParser parser = new TextFieldParser(@"c:\temp\test.csv"))
{
    parser.TextFieldType = FieldType.Delimited;
    parser.SetDelimiters(",");
    while (!parser.EndOfData)
    {
        //Process row
        string[] fields = parser.ReadFields();
        foreach (string field in fields)
        {
            //TODO: Process field
        }
    }
}

I documenti sono qui - Classe TextFieldParser

PS Se hai bisogno di un esportatore CSV , prova CsvExport (scopri: sono uno dei collaboratori)


2
Dalla mia esperienza, TextFieldParser non funziona bene con file di grandi dimensioni (ad es.> 250 Mb). :(
MBoros,

6
TextFieldParser implementa IDisposable, quindi potrebbe essere meglio usarlo in una clausola using. Buona risposta altrimenti.
Chris Bush,

3
Nel costruttore potresti voler utilizzare una codifica diversa da quella predefinita, in questo modo: new TextFieldParser ("c: \ temp \ test.csv", System.Text.Encoding.UTF8)
neural5torm

1
Nota che se un campo nel tuo CSV contiene righe vuote, verranno saltate da TextFieldParser.ReadLine(). Vedi i documenti TextFieldParser
mcNux,

3
C'è un modo per ottenerlo in .NET Core?
Hugo Zink,

183

CsvHelper (una libreria che mantengo) leggerà un file CSV in oggetti personalizzati.

var csv = new CsvReader( File.OpenText( "file.csv" ) );
var myCustomObjects = csv.GetRecords<MyCustomObject>();

A volte non possiedi gli oggetti che stai cercando di leggere. In questo caso, è possibile utilizzare la mappatura fluida perché non è possibile inserire attributi nella classe.

public sealed class MyCustomObjectMap : CsvClassMap<MyCustomObject>
{
    public MyCustomObjectMap()
    {
        Map( m => m.Property1 ).Name( "Column Name" );
        Map( m => m.Property2 ).Index( 4 );
        Map( m => m.Property3 ).Ignore();
        Map( m => m.Property4 ).TypeConverter<MySpecialTypeConverter>();
    }
}

MODIFICARE:

CsvReader ora richiede che CultureInfo sia passato al constuctor ( https://github.com/JoshClose/CsvHelper/issues/1441 ).

Esempio:

var csv = new CsvReader(File.OpenText("file.csv"), System.Globalization.CultureInfo.CurrentCulture);

18
Sono d'accordo con @ kubal5003. Ciò che mi ha venduto è che lo hai disponibile come pacchetto NuGet. Grazie amico, è veloce e fa tutta la lettura CSV di cui ho bisogno.
Gromer,

7
È dannatamente veloce. 1,3 milioni di dischi letti e deserializzati in 10 secondi.
Marisks

2
Grande libreria molto facile da implementare. Vorrei solo suggerire a Josh di aggiornare la sua risposta qui perché la libreria è cambiata un po 'da quando questa risposta è stata scritta e non è più possibile creare un'istanza di CsvHelper (ora è solo uno spazio dei nomi) ma è necessario utilizzare la classe CsvReader.
Marko,

1
CsvClassMap non sembra esistere nell'ultima versione di CsvHelper?
Knocte,

1
knocte, ora si chiama ClassMap. Ci sono anche altre modifiche, come dover fare una lettura prima di chiedere il record di intestazione (che tra l'altro viene impostato su ciò che è stato letto dalla prima chiamata a Read ()). Come altri hanno già detto prima, è superveloce e facile da lavorare.
Norgie,

31

In un'applicazione aziendale, utilizzo il progetto Open Source su codeproject.com, CSVReader .

Funziona bene e ha buone prestazioni. C'è qualche benchmarking sul link che ho fornito.

Un semplice esempio, copiato dalla pagina del progetto:

using (CsvReader csv = new CsvReader(new StreamReader("data.csv"), true))
{
    int fieldCount = csv.FieldCount;
    string[] headers = csv.GetFieldHeaders();

    while (csv.ReadNextRecord())
    {
        for (int i = 0; i < fieldCount; i++)
            Console.Write(string.Format("{0} = {1};", headers[i], csv[i]));

        Console.WriteLine();
    }
}

Come puoi vedere, è molto facile lavorare con.



12

Se hai solo bisogno di leggere i file CSV, ti consiglio questa libreria: un lettore CSV veloce
Se devi anche generare file CSV, usa questo: FileHelpers

Entrambi sono gratuiti e opensource.


FileHelpers ha un riassunto accattivante: filehelpers.com FileHelpers è una libreria .NET gratuita e facile da usare per importare / esportare dati da record a lunghezza fissa o delimitati in file, stringhe o flussi.
AnneTheAgile,

Sebbene questo link possa rispondere alla domanda, solo le risposte del link sono scoraggiate su Stack Overflow, puoi migliorare questa risposta prendendo parti vitali del link e inserendolo nella tua risposta, questo assicura che la tua risposta sia ancora una risposta se il link viene cambiato o rimosso :)
WhatsThePoint il

11

Ecco una classe di aiuto che uso spesso, nel caso in cui qualcuno ritorni a questo thread (volevo condividerlo).

Lo uso per la semplicità di portarlo in progetti pronti all'uso:

public class CSVHelper : List<string[]>
{
  protected string csv = string.Empty;
  protected string separator = ",";

  public CSVHelper(string csv, string separator = "\",\"")
  {
    this.csv = csv;
    this.separator = separator;

    foreach (string line in Regex.Split(csv, System.Environment.NewLine).ToList().Where(s => !string.IsNullOrEmpty(s)))
    {
      string[] values = Regex.Split(line, separator);

      for (int i = 0; i < values.Length; i++)
      {
        //Trim values
        values[i] = values[i].Trim('\"');
      }

      this.Add(values);
    }
  }
}

E usalo come:

public List<Person> GetPeople(string csvContent)
{
  List<Person> people = new List<Person>();
  CSVHelper csv = new CSVHelper(csvContent);
  foreach(string[] line in csv)
  {
    Person person = new Person();
    person.Name = line[0];
    person.TelephoneNo = line[1];
    people.Add(person);
  }
  return people;
}

[Assistente csv aggiornato: bug risolto in cui l'ultimo carattere di nuova riga ha creato una nuova linea]


17
se una delle voci CSV contiene virgola (,) questo codice non funzionerà.
Hakan,

Per mantenere le cose leggere, ho usato un personaggio di pipa come separatore. '|'
Base33,

soluzione eccellente. Solo una domanda sul secondo frammento. Che tipo di oggetto è Person
Cocoa Dev il

@CocoaDev È una classe che contiene due proprietà di stringa: Nome e Telefono. Puramente per l'esempio però. Se una delle proprietà era un numero intero, dovrebbe essere solo una conversione diretta (con segno di spunta?).
Base33,

10

Questa soluzione utilizza l' assembly ufficiale Microsoft.VisualBasic per analizzare CSV.

vantaggi:

  • fuga del delimitatore
  • ignora l'intestazione
  • spazi di assetto
  • ignora i commenti

Codice:

    using Microsoft.VisualBasic.FileIO;

    public static List<List<string>> ParseCSV (string csv)
    {
        List<List<string>> result = new List<List<string>>();


        // To use the TextFieldParser a reference to the Microsoft.VisualBasic assembly has to be added to the project. 
        using (TextFieldParser parser = new TextFieldParser(new StringReader(csv))) 
        {
            parser.CommentTokens = new string[] { "#" };
            parser.SetDelimiters(new string[] { ";" });
            parser.HasFieldsEnclosedInQuotes = true;

            // Skip over header line.
            //parser.ReadLine();

            while (!parser.EndOfData)
            {
                var values = new List<string>();

                var readFields = parser.ReadFields();
                if (readFields != null)
                    values.AddRange(readFields);
                result.Add(values);
            }
        }

        return result;
    }

7

Ho scritto TinyCsvParser per .NET, che è uno dei parser .NET più veloci in circolazione e altamente configurabile per analizzare quasi tutti i formati CSV.

È rilasciato sotto licenza MIT:

NuGet può essere utilizzato per installarlo. Eseguire il comando seguente nella console di Gestione pacchetti .

PM> Install-Package TinyCsvParser

uso

Immagina di avere un elenco di persone in un file CSV persons.csvcon il loro nome, cognome e data di nascita.

FirstName;LastName;BirthDate
Philipp;Wagner;1986/05/12
Max;Musterman;2014/01/02

Il modello di dominio corrispondente nel nostro sistema potrebbe apparire così.

private class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}

Quando si utilizza TinyCsvParser è necessario definire il mapping tra le colonne nei dati CSV e la proprietà nel modello di dominio.

private class CsvPersonMapping : CsvMapping<Person>
{

    public CsvPersonMapping()
        : base()
    {
        MapProperty(0, x => x.FirstName);
        MapProperty(1, x => x.LastName);
        MapProperty(2, x => x.BirthDate);
    }
}

E quindi possiamo usare la mappatura per analizzare i dati CSV con a CsvParser.

namespace TinyCsvParser.Test
{
    [TestFixture]
    public class TinyCsvParserTest
    {
        [Test]
        public void TinyCsvTest()
        {
            CsvParserOptions csvParserOptions = new CsvParserOptions(true, new[] { ';' });
            CsvPersonMapping csvMapper = new CsvPersonMapping();
            CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper);

            var result = csvParser
                .ReadFromFile(@"persons.csv", Encoding.ASCII)
                .ToList();

            Assert.AreEqual(2, result.Count);

            Assert.IsTrue(result.All(x => x.IsValid));

            Assert.AreEqual("Philipp", result[0].Result.FirstName);
            Assert.AreEqual("Wagner", result[0].Result.LastName);

            Assert.AreEqual(1986, result[0].Result.BirthDate.Year);
            Assert.AreEqual(5, result[0].Result.BirthDate.Month);
            Assert.AreEqual(12, result[0].Result.BirthDate.Day);

            Assert.AreEqual("Max", result[1].Result.FirstName);
            Assert.AreEqual("Mustermann", result[1].Result.LastName);

            Assert.AreEqual(2014, result[1].Result.BirthDate.Year);
            Assert.AreEqual(1, result[1].Result.BirthDate.Month);
            Assert.AreEqual(1, result[1].Result.BirthDate.Day);
        }
    }
}

Guida utente

Una guida per l'utente completa è disponibile all'indirizzo:


1

Ecco la mia implementazione KISS ...

using System;
using System.Collections.Generic;
using System.Text;

class CsvParser
{
    public static List<string> Parse(string line)
    {
        const char escapeChar = '"';
        const char splitChar = ',';
        bool inEscape = false;
        bool priorEscape = false;

        List<string> result = new List<string>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < line.Length; i++)
        {
            char c = line[i];
            switch (c)
            {
                case escapeChar:
                    if (!inEscape)
                        inEscape = true;
                    else
                    {
                        if (!priorEscape)
                        {
                            if (i + 1 < line.Length && line[i + 1] == escapeChar)
                                priorEscape = true;
                            else
                                inEscape = false;
                        }
                        else
                        {
                            sb.Append(c);
                            priorEscape = false;
                        }
                    }
                    break;
                case splitChar:
                    if (inEscape) //if in escape
                        sb.Append(c);
                    else
                    {
                        result.Add(sb.ToString());
                        sb.Length = 0;
                    }
                    break;
                default:
                    sb.Append(c);
                    break;
            }
        }

        if (sb.Length > 0)
            result.Add(sb.ToString());

        return result;
    }

}

1
Questo non riguarda le interruzioni di riga all'interno delle stringhe tra virgolette valide in un file CSV.
John Leidegren,

Alex, quello che John sta cercando di dire è che RFC 4180 ( ietf.org/rfc/rfc4180.txt - Vedi la sezione 2 e il punto 6) consente a una colonna di avere un CR LF nel mezzo di una colonna che lo sta effettivamente diffondendo 2 righe in un file. La tua soluzione probabilmente funzionerà bene nella maggior parte dei casi (specialmente se i file CSV sono stati creati salvando da Excel), ma non copre questo caso limite. CsvHelper, menzionato sopra, dovrebbe prendere in considerazione questo caso.
David Yates,

Sì, questo è vero, ma se hai CR LF nel tuo CSV, probabilmente non dovresti usare CSV, ma qualcosa di più appropriato come, json o xml, o un formato a lunghezza fissa.
Alex ha iniziato l'

1

Qualche tempo fa avevo scritto lezioni semplici per CSV in lettura / scrittura basate sulla Microsoft.VisualBasiclibreria. Usando questa semplice classe sarai in grado di lavorare con CSV come con un array di 2 dimensioni. Puoi trovare la mia classe al seguente link: https://github.com/ukushu/DataExporter

Semplice esempio di utilizzo:

Csv csv = new Csv("\t");//delimiter symbol

csv.FileOpen("c:\\file1.csv");

var row1Cell6Value = csv.Rows[0][5];

csv.AddRow("asdf","asdffffff","5")

csv.FileSave("c:\\file2.csv");

Per leggere l'intestazione devi solo leggere le csv.Rows[0]celle :)


1

Soluzione di file a sorgente singola per esigenze di analisi semplici, utile. Si occupa di tutti i cattivi casi limite. Come la normalizzazione di nuove linee e la gestione di nuove linee in valori letterali di stringa tra virgolette. Prego!

Se il tuo file CSV ha un'intestazione, leggi i nomi delle colonne (e calcola gli indici delle colonne) dalla prima riga. Semplice come quella.

Si noti che Dumpè un metodo LINQPad, è possibile rimuoverlo se non si utilizza LINQPad.

void Main()
{
    var file1 = "a,b,c\r\nx,y,z";
    CSV.ParseText(file1).Dump();

    var file2 = "a,\"b\",c\r\nx,\"y,z\"";
    CSV.ParseText(file2).Dump();

    var file3 = "a,\"b\",c\r\nx,\"y\r\nz\"";
    CSV.ParseText(file3).Dump();

    var file4 = "\"\"\"\"";
    CSV.ParseText(file4).Dump();
}

static class CSV
{
    public struct Record
    {
        public readonly string[] Row;

        public string this[int index] => Row[index];

        public Record(string[] row)
        {
            Row = row;
        }
    }

    public static List<Record> ParseText(string text)
    {
        return Parse(new StringReader(text));
    }

    public static List<Record> ParseFile(string fn)
    {
        using (var reader = File.OpenText(fn))
        {
            return Parse(reader);
        }
    }

    public static List<Record> Parse(TextReader reader)
    {
        var data = new List<Record>();

        var col = new StringBuilder();
        var row = new List<string>();
        for (; ; )
        {
            var ln = reader.ReadLine();
            if (ln == null) break;
            if (Tokenize(ln, col, row))
            {
                data.Add(new Record(row.ToArray()));
                row.Clear();
            }
        }

        return data;
    }

    public static bool Tokenize(string s, StringBuilder col, List<string> row)
    {
        int i = 0;

        if (col.Length > 0)
        {
            col.AppendLine(); // continuation

            if (!TokenizeQuote(s, ref i, col, row))
            {
                return false;
            }
        }

        while (i < s.Length)
        {
            var ch = s[i];
            if (ch == ',')
            {
                row.Add(col.ToString().Trim());
                col.Length = 0;
                i++;
            }
            else if (ch == '"')
            {
                i++;
                if (!TokenizeQuote(s, ref i, col, row))
                {
                    return false;
                }
            }
            else
            {
                col.Append(ch);
                i++;
            }
        }

        if (col.Length > 0)
        {
            row.Add(col.ToString().Trim());
            col.Length = 0;
        }

        return true;
    }

    public static bool TokenizeQuote(string s, ref int i, StringBuilder col, List<string> row)
    {
        while (i < s.Length)
        {
            var ch = s[i];
            if (ch == '"')
            {
                // escape sequence
                if (i + 1 < s.Length && s[i + 1] == '"')
                {
                    col.Append('"');
                    i++;
                    i++;
                    continue;
                }
                i++;
                return true;
            }
            else
            {
                col.Append(ch);
                i++;
            }
        }
        return false;
    }
}

1

Un altro di questo elenco, Cinchoo ETL - una libreria open source per leggere e scrivere più formati di file (CSV, file flat, Xml, JSON ecc.)

L'esempio seguente mostra come leggere rapidamente il file CSV (nessun oggetto POCO richiesto)

string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

using (var p = ChoCSVReader.LoadText(csv)
    .WithFirstLineHeader()
    )
{
    foreach (var rec in p)
    {
        Console.WriteLine($"Id: {rec.Id}");
        Console.WriteLine($"Name: {rec.Name}");
    }
}

L'esempio seguente mostra come leggere il file CSV usando l'oggetto POCO

public partial class EmployeeRec
{
    public int Id { get; set; }
    public string Name { get; set; }
}

static void CSVTest()
{
    string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

    using (var p = ChoCSVReader<EmployeeRec>.LoadText(csv)
        .WithFirstLineHeader()
        )
    {
        foreach (var rec in p)
        {
            Console.WriteLine($"Id: {rec.Id}");
            Console.WriteLine($"Name: {rec.Name}");
        }
    }
}

Consulta gli articoli su CodeProject su come utilizzarlo.


0

Basato sul post di unlimit su Come dividere correttamente un CSV usando la funzione split # (C #)? :

string[] tokens = System.Text.RegularExpressions.Regex.Split(paramString, ",");

NOTA: questo non gestisce le virgole di escape / nidificate, ecc., Quindi è adatto solo per alcuni semplici elenchi CSV.


2
Questo è molto brutto e probabilmente lento :)
EKS

1
Probabilmente, ma funziona perfettamente e semplicemente per un piccolo set di parametri, quindi è una soluzione valida e utile. Perché ridimensionarlo? "Very Bad" è un po 'estremo, non credi?
Radsdau,

1
Non gestisce le virgole di escape / nidificate, ecc. Funzionerà in alcuni casi ma sicuramente non funzionerà per tutti i file CSV
NStuke

Hai ragione; Modificherò la risposta per riflettere ciò. Grazie. Ma ha ancora il suo posto.
Radsdau,

Questo ha funzionato perfettamente per il mio caso d'uso in cui sto costruendo un server SQL Cll DLL e non posso usare nessuno di questi altri pacchetti esterni. Avevo solo bisogno di analizzare un semplice file CSV con un nome di file e il conteggio delle righe.
dubvfan87,

0

Questo codice legge CSV su DataTable:

public static DataTable ReadCsv(string path)
{
    DataTable result = new DataTable("SomeData");
    using (TextFieldParser parser = new TextFieldParser(path))
    {
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");
        bool isFirstRow = true;
        //IList<string> headers = new List<string>();

        while (!parser.EndOfData)
        {
            string[] fields = parser.ReadFields();
            if (isFirstRow)
            {
                foreach (string field in fields)
                {
                    result.Columns.Add(new DataColumn(field, typeof(string)));
                }
                isFirstRow = false;
            }
            else
            {
                int i = 0;
                DataRow row = result.NewRow();
                foreach (string field in fields)
                {
                    row[i++] = field;
                }
                result.Rows.Add(row);
            }
        }
    }
    return result;
}

1
TextFieldParser è in Microsoft.VisualBasic.dll.
user3285954

0

Se qualcuno desidera uno snippet, può inserire il proprio codice senza dover associare una libreria o scaricare un pacchetto. Ecco una versione che ho scritto:

    public static string FormatCSV(List<string> parts)
    {
        string result = "";

        foreach (string s in parts)
        {
            if (result.Length > 0)
            {
                result += ",";

                if (s.Length == 0)
                    continue;
            }

            if (s.Length > 0)
            {
                result += "\"" + s.Replace("\"", "\"\"") + "\"";
            }
            else
            {
                // cannot output double quotes since its considered an escape for a quote
                result += ",";
            }
        }

        return result;
    }

    enum CSVMode
    {
        CLOSED = 0,
        OPENED_RAW = 1,
        OPENED_QUOTE = 2
    }

    public static List<string> ParseCSV(string input)
    {
        List<string> results;

        CSVMode mode;

        char[] letters;

        string content;


        mode = CSVMode.CLOSED;

        content = "";
        results = new List<string>();
        letters = input.ToCharArray();

        for (int i = 0; i < letters.Length; i++)
        {
            char letter = letters[i];
            char nextLetter = '\0';

            if (i < letters.Length - 1)
                nextLetter = letters[i + 1];

            // If its a quote character
            if (letter == '"')
            {
                // If that next letter is a quote
                if (nextLetter == '"' && mode == CSVMode.OPENED_QUOTE)
                {
                    // Then this quote is escaped and should be added to the content

                    content += letter;

                    // Skip the escape character
                    i++;
                    continue;
                }
                else
                {
                    // otherwise its not an escaped quote and is an opening or closing one
                    // Character is skipped

                    // If it was open, then close it
                    if (mode == CSVMode.OPENED_QUOTE)
                    {
                        results.Add(content);

                        // reset the content
                        content = "";

                        mode = CSVMode.CLOSED;

                        // If there is a next letter available
                        if (nextLetter != '\0')
                        {
                            // If it is a comma
                            if (nextLetter == ',')
                            {
                                i++;
                                continue;
                            }
                            else
                            {
                                throw new Exception("Expected comma. Found: " + nextLetter);
                            }
                        }
                    }
                    else if (mode == CSVMode.OPENED_RAW)
                    {
                        // If it was opened raw, then just add the quote 
                        content += letter;
                    }
                    else if (mode == CSVMode.CLOSED)
                    {
                        // Otherwise open it as a quote 

                        mode = CSVMode.OPENED_QUOTE;
                    }
                }
            }
            // If its a comma seperator
            else if (letter == ',')
            {
                // If in quote mode
                if (mode == CSVMode.OPENED_QUOTE)
                {
                    // Just read it
                    content += letter;
                }
                // If raw, then close the content
                else if (mode == CSVMode.OPENED_RAW)
                {
                    results.Add(content);

                    content = "";

                    mode = CSVMode.CLOSED;
                }
                // If it was closed, then open it raw
                else if (mode == CSVMode.CLOSED)
                {
                    mode = CSVMode.OPENED_RAW;

                    results.Add(content);

                    content = "";
                }
            }
            else
            {
                // If opened quote, just read it
                if (mode == CSVMode.OPENED_QUOTE)
                {
                    content += letter;
                }
                // If opened raw, then read it
                else if (mode == CSVMode.OPENED_RAW)
                {
                    content += letter;
                }
                // It closed, then open raw
                else if (mode == CSVMode.CLOSED)
                {
                    mode = CSVMode.OPENED_RAW;

                    content += letter;
                }
            }
        }

        // If it was still reading when the buffer finished
        if (mode != CSVMode.CLOSED)
        {
            results.Add(content);
        }

        return results;
    }

0

Ecco una soluzione breve e semplice.

                using (TextFieldParser parser = new TextFieldParser(outputLocation))
                 {
                        parser.TextFieldType = FieldType.Delimited;
                        parser.SetDelimiters(",");
                        string[] headers = parser.ReadLine().Split(',');
                        foreach (string header in headers)
                        {
                            dataTable.Columns.Add(header);
                        }
                        while (!parser.EndOfData)
                        {
                            string[] fields = parser.ReadFields();
                            dataTable.Rows.Add(fields);
                        }
                    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.