web-dev-qa-db-fra.com

Lecture de fichier CSV et stockage de valeurs dans un tableau

J'essaie de lire un fichier *.csv-.

Le fichier *.csv- est composé de deux colonnes séparées par un point-virgule ("; "). 

Je peux lire le fichier *.csv- à l'aide de StreamReader et séparer chaque ligne à l'aide de la fonction Split(). Je veux stocker chaque colonne dans un tableau séparé, puis l'afficher. 

Est-il possible de faire ça?

252
Rushabh Shah

Vous pouvez le faire comme ça:

using System.IO;

static void Main(string[] args)
{
    using(var reader = new StreamReader(@"C:\test.csv"))
    {
        List<string> listA = new List<string>();
        List<string> listB = new List<string>();
        while (!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            var values = line.Split(';');

            listA.Add(values[0]);
            listB.Add(values[1]);
        }
    }
}
323
Michael M.

Mon analyseur CSV préféré est celui intégré à la bibliothèque .net. Il s'agit d'un trésor caché à l'intérieur de l'espace de noms Microsoft.VisualBasic . Vous trouverez ci-dessous un exemple de code:

using Microsoft.VisualBasic.FileIO;

var path = @"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
 csvParser.CommentTokens = new string[] { "#" };
 csvParser.SetDelimiters(new string[] { "," });
 csvParser.HasFieldsEnclosedInQuotes = true;

 // Skip the row with the column names
 csvParser.ReadLine();

 while (!csvParser.EndOfData)
 {
  // Read current line fields, pointer moves to the next line.
  string[] fields = csvParser.ReadFields();
  string Name = fields[0];
  string Address = fields[1];
 }
}

N'oubliez pas d'ajouter une référence à Microsoft.VisualBasic

Plus de détails sur l'analyseur sont donnés ici: http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html

113
Habeeb

Façon LINQ: 

var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
          select (from piece in line
                  select piece);

^^ Wrong - Edit by Nick

Il semble que le répondant d'origine tentait de peupler csv avec un tableau à 2 dimensions - un tableau contenant des tableaux. Chaque élément du premier tableau contient un tableau représentant ce numéro de ligne, chaque élément du tableau imbriqué contenant les données de cette colonne spécifique.

var csv = from line in lines
          select (line.Split(',')).ToArray();
71
as-cii

J'utilise habituellement cet analyseur de codeproject , car il y a un tas d'échappements de caractères et similaires qu'il gère pour moi.

32
Paul

Voici ma variante de la réponse la plus votée:

var contents = File.ReadAllText(filename).Split('\n');
var csv = from line in contents
          select line.Split(',').ToArray();

La variable csv peut ensuite être utilisée comme dans l'exemple suivant:

int headerRows = 5;
foreach (var row in csv.Skip(headerRows)
    .TakeWhile(r => r.Length > 1 && r.Last().Trim().Length > 0))
{
    String zerothColumnValue = row[0]; // leftmost column
    var firstColumnValue = row[1];
}
29
tomsv

Je viens de trouver cette bibliothèque: https://github.com/JoshClose/CsvHelper

Très intuitif et facile à utiliser. A aussi un paquet de nuget qui est rapide à mettre en œuvre: http://nuget.org/packages/CsvHelper/1.17.0 . Semble également être activement maintenu que j'aime bien.

La configuration pour utiliser un point-virgule est simple: https://github.com/JoshClose/CsvHelper/wiki/Custom-Configurations

26
joshb

Vous ne pouvez pas créer un tableau immédiatement car vous devez connaître le nombre de lignes depuis le début (et cela nécessiterait de lire le fichier csv deux fois).

Vous pouvez stocker des valeurs dans deux List<T> puis les utiliser ou les convertir en tableau à l’aide de List<T>.ToArray().

Exemple très simple:

var column1 = new List<string>();
var column2 = new List<string>();
using (var rd = new StreamReader("filename.csv"))
{
    while (!rd.EndOfStream)
    {
        var splits = rd.ReadLine().Split(';');
        column1.Add(splits[0]);
        column2.Add(splits[1]);
    }
}
// print column1
Console.WriteLine("Column 1:");
foreach (var element in column1)
    Console.WriteLine(element);

// print column2
Console.WriteLine("Column 2:");
foreach (var element in column2)
    Console.WriteLine(element);

N.B.

S'il vous plaît noter que ceci est juste un exemple très simple . L'utilisation de string.Split ne prend pas en compte les cas où certains enregistrements contiennent le séparateur ; à l'intérieur.
Pour une approche plus sûre, envisagez l’utilisation de bibliothèques spécifiques à csv, telles que CsvHelper sur nuget.

24
digEmAll

Si vous devez sauter des lignes et/ou des colonnes (en-tête), vous pouvez utiliser ceci pour créer un tableau à 2 dimensions:

    var lines = File.ReadAllLines(path).Select(a => a.Split(';'));
    var csv = (from line in lines               
               select (from col in line
               select col).Skip(1).ToArray() // skip the first column
              ).Skip(2).ToArray(); // skip 2 headlines

Ceci est très utile si vous avez besoin de façonner les données avant de les traiter davantage (en supposant que les 2 premières lignes sont constituées du titre et que la première colonne est un titre de ligne - que vous n’avez pas besoin d’avoir dans le tableau vouloir regarder les données).

N.B. Vous pouvez facilement obtenir les titres et la 1ère colonne en utilisant le code suivant:

    var coltitle = (from line in lines 
                    select line.Skip(1).ToArray() // skip 1st column
                   ).Skip(1).Take(1).FirstOrDefault().ToArray(); // take the 2nd row
    var rowtitle = (from line in lines select line[0] // take 1st column
                   ).Skip(2).ToArray(); // skip 2 headlines

Cet exemple de code suppose la structure suivante de votre fichier *.csv:

CSV Matrix

Remarque: Si vous devez ignorer les lignes vides - ce qui peut parfois être pratique, vous pouvez le faire en insérant

    where line.Any(a=>!string.IsNullOrWhiteSpace(a))

entre les instructions from et select dans les exemples de codeLINQci-dessus.

11
Matt

Vous pouvez utiliser Microsoft.VisualBasic.FileIO.TextFieldParser dll en C # pour de meilleures performances. 

obtenir ci-dessous exemple de code de l'article ci-dessus

static void Main()
{
    string csv_file_path=@"C:\Users\Administrator\Desktop\test.csv";

    DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);

    Console.WriteLine("Rows count:" + csvData.Rows.Count);

    Console.ReadLine();
}


private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
    DataTable csvData = new DataTable();

    try
    {

    using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
        {
            csvReader.SetDelimiters(new string[] { "," });
            csvReader.HasFieldsEnclosedInQuotes = true;
            string[] colFields = csvReader.ReadFields();
            foreach (string column in colFields)
            {
                DataColumn datecolumn = new DataColumn(column);
                datecolumn.AllowDBNull = true;
                csvData.Columns.Add(datecolumn);
            }

            while (!csvReader.EndOfData)
            {
                string[] fieldData = csvReader.ReadFields();
                //Making empty value as null
                for (int i = 0; i < fieldData.Length; i++)
                {
                    if (fieldData[i] == "")
                    {
                        fieldData[i] = null;
                    }
                }
                csvData.Rows.Add(fieldData);
            }
        }
    }
    catch (Exception ex)
    {
    }
    return csvData;
}
9
kombsh

Bonjour à tous, j’ai créé une classe statique pour ce faire . + Vérification des colonnes + Suppression du signe de quota

public static class CSV
{
    public static List<string[]> Import(string file, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
    {
        return ReadCSVFile(file, csvDelimiter, ignoreHeadline, removeQuoteSign);
    }

    private static List<string[]> ReadCSVFile(string filename, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
    {
        string[] result = new string[0];
        List<string[]> lst = new List<string[]>();

        string line;
        int currentLineNumner = 0;
        int columnCount = 0;

        // Read the file and display it line by line.  
        using (System.IO.StreamReader file = new System.IO.StreamReader(filename))
        {
            while ((line = file.ReadLine()) != null)
            {
                currentLineNumner++;
                string[] strAr = line.Split(csvDelimiter);
                // save column count of dirst line
                if (currentLineNumner == 1)
                {
                    columnCount = strAr.Count();
                }
                else
                {
                    //Check column count of every other lines
                    if (strAr.Count() != columnCount)
                    {
                        throw new Exception(string.Format("CSV Import Exception: Wrong column count in line {0}", currentLineNumner));
                    }
                }

                if (removeQuoteSign) strAr = RemoveQouteSign(strAr);

                if (ignoreHeadline)
                {
                    if(currentLineNumner !=1) lst.Add(strAr);
                }
                else
                {
                    lst.Add(strAr);
                }
            }

        }

        return lst;
    }
    private static string[] RemoveQouteSign(string[] ar)
    {
        for (int i = 0;i< ar.Count() ; i++)
        {
            if (ar[i].StartsWith("\"") || ar[i].StartsWith("'")) ar[i] = ar[i].Substring(1);
            if (ar[i].EndsWith("\"") || ar[i].EndsWith("'")) ar[i] = ar[i].Substring(0,ar[i].Length-1);

        }
        return ar;
    }

}
4
Mathias Schmidt

Voici un cas particulier où l'un des champs de données comporte un point-virgule (";") dans ses données. Dans ce cas, la plupart des réponses ci-dessus échoueront.

Solution ce cas sera 

string[] csvRows = System.IO.File.ReadAllLines(FullyQaulifiedFileName);
string[] fields = null;
List<string> lstFields;
string field;
bool quoteStarted = false;
foreach (string csvRow in csvRows)
{
    lstFields = new List<string>();
    field = "";
    for (int i = 0; i < csvRow.Length; i++)
    {
        string tmp = csvRow.ElementAt(i).ToString();
        if(String.Compare(tmp,"\"")==0)
        {
            quoteStarted = !quoteStarted;
        }
        if (String.Compare(tmp, ";") == 0 && !quoteStarted)
        {
            lstFields.Add(field);
            field = "";
        }
        else if (String.Compare(tmp, "\"") != 0)
        {
            field += tmp;
        }
    }
    if(!string.IsNullOrEmpty(field))
    {
        lstFields.Add(field);
        field = "";
    }
// This will hold values for each column for current row under processing
    fields = lstFields.ToArray(); 
}
4
Yogesh
var firstColumn = new List<string>();
var lastColumn = new List<string>();

// your code for reading CSV file

foreach(var line in file)
{
    var array = line.Split(';');
    firstColumn.Add(array[0]);
    lastColumn.Add(array[1]);
}

var firstArray = firstColumn.ToArray();
var lastArray = lastColumn.ToArray();
3
Jakub Konecki

La bibliothèque open-source Angara.Table permet de charger des fichiers CSV dans des colonnes typées afin que vous puissiez obtenir les tableaux à partir des colonnes. Chaque colonne peut être indexée à la fois par nom ou par index. Voir http://predictionmachines.github.io/Angara.Table/saveload.html .

La bibliothèque suit RFC4180 pour CSV; il permet l'inférence de type et les chaînes multilignes.

Exemple:

using System.Collections.Immutable;
using Angara.Data;
using Angara.Data.DelimitedFile;

...

ReadSettings settings = new ReadSettings(Delimiter.Semicolon, false, true, null, null);
Table table = Table.Load("data.csv", settings);
ImmutableArray<double> a = table["double-column-name"].Rows.AsReal;

for(int i = 0; i < a.Length; i++)
{
    Console.WriteLine("{0}: {1}", i, a[i]);
}

Vous pouvez voir un type de colonne en utilisant le type Column, par exemple.

Column c = table["double-column-name"];
Console.WriteLine("Column {0} is double: {1}", c.Name, c.Rows.IsRealColumn);

Comme la bibliothèque est concentrée sur F #, vous devrez peut-être ajouter une référence à FSharp.Core 4.4 Assembly; Cliquez sur "Ajouter une référence" dans le projet et choisissez FSharp.Core 4.4 sous "Assemblies" -> "Extensions".

2

Je suis juste un étudiant en train de travailler sur ma thèse de maîtrise, mais c'est ainsi que je l'ai résolue et cela a bien fonctionné pour moi. Tout d’abord, vous sélectionnez votre fichier à partir du répertoire (uniquement au format csv), puis vous placez les données dans les listes.

List<float> t = new List<float>();
List<float> SensorI = new List<float>();
List<float> SensorII = new List<float>();
List<float> SensorIII = new List<float>();
using (OpenFileDialog dialog = new OpenFileDialog())
{
    try
    {
        dialog.Filter = "csv files (*.csv)|*.csv";
        dialog.Multiselect = false;
        dialog.InitialDirectory = ".";
        dialog.Title = "Select file (only in csv format)";
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            var fs = File.ReadAllLines(dialog.FileName).Select(a => a.Split(';'));
            int counter = 0;
            foreach (var line in fs)
            {
                counter++;
                if (counter > 2)    // Skip first two headder lines
                {
                    this.t.Add(float.Parse(line[0]));
                    this.SensorI.Add(float.Parse(line[1]));
                    this.SensorII.Add(float.Parse(line[2]));
                    this.SensorIII.Add(float.Parse(line[3]));
                }
            }
        }
    }
    catch (Exception exc)
    {
        MessageBox.Show(
            "Error while opening the file.\n" + exc.Message, 
            this.Text, 
            MessageBoxButtons.OK, 
            MessageBoxIcon.Error
        );
    }
}
1
Daniel

J'utilise csvreader.com (composant payant) depuis des années et je n'ai jamais eu de problème. Il est solide, petit et rapide, mais vous devez le payer. Vous pouvez définir le délimiteur à votre guise.

using (CsvReader reader = new CsvReader(s) {
    reader.Settings.Delimiter = ';';
    reader.ReadHeaders();  // if headers on a line by themselves.  Makes reader.Headers[] available
    while (reader.ReadRecord())
        ... use reader.Values[col_i] ...
}
1
Oliver Bock

Toujours incorrecte. Vous devez compenser "" entre guillemets . Voici ma solution style Microsoft CSV.

               /// <summary>
    /// Microsoft style csv file.  " is the quote character, "" is an escaped quote.
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="sepChar"></param>
    /// <param name="quoteChar"></param>
    /// <param name="escChar"></param>
    /// <returns></returns>
    public static List<string[]> ReadCSVFileMSStyle(string fileName, char sepChar = ',', char quoteChar = '"')
    {
        List<string[]> ret = new List<string[]>();

        string[] csvRows = System.IO.File.ReadAllLines(fileName);

        foreach (string csvRow in csvRows)
        {
            bool inQuotes = false;
            List<string> fields = new List<string>();
            string field = "";
            for (int i = 0; i < csvRow.Length; i++)
            {
                if (inQuotes)
                {
                    // Is it a "" inside quoted area? (escaped litteral quote)
                    if(i < csvRow.Length - 1 && csvRow[i] == quoteChar && csvRow[i+1] == quoteChar)
                    {
                        i++;
                        field += quoteChar;
                    }
                    else if(csvRow[i] == quoteChar)
                    {
                        inQuotes = false;
                    }
                    else
                    {
                        field += csvRow[i];
                    }
                }
                else // Not in quoted region
                {
                     if (csvRow[i] == quoteChar)
                    {
                        inQuotes = true;
                    }
                    if (csvRow[i] == sepChar)
                    {
                        fields.Add(field);
                        field = "";
                    }
                    else 
                    {
                        field += csvRow[i];
                    }
                }
            }
            if (!string.IsNullOrEmpty(field))
            {
                fields.Add(field);
                field = "";
            }
            ret.Add(fields.ToArray());
        }

        return ret;
    }
}
0
R Keene

J'ai passé quelques heures à chercher une bonne bibliothèque, mais j'ai finalement écrit mon propre code :) Vous pouvez lire le fichier (ou la base de données) avec tous les outils de votre choix, puis appliquer la routine suivante à chaque ligne:

private static string[] SmartSplit(string line, char separator = ',')
{
    var inQuotes = false;
    var token = "";
    var lines = new List<string>();
    for (var i = 0; i < line.Length; i++) {
        var ch = line[i];
        if (inQuotes) // process string in quotes, 
        {
            if (ch == '"') {
                if (i<line.Length-1 && line[i + 1] == '"') {
                    i++;
                    token += '"';
                }
                else inQuotes = false;
            } else token += ch;
        } else {
            if (ch == '"') inQuotes = true;
            else if (ch == separator) {
                lines.Add(token);
                token = "";
                } else token += ch;
            }
    }
    lines.Add(token);
    return lines.ToArray();
}
0
Zbyszek Swirski

J'ai une bibliothèque qui fait exactement ce dont vous avez besoin.

Il y a quelque temps, j'avais écrit une bibliothèque assez simple et rapide pour travailler avec des fichiers CSV. Vous pouvez le trouver en cliquant sur le lien suivant: https://github.com/ukushu/DataExporter

Cela fonctionne avec CSV comme avec le tableau à 2 dimensions. Exactement comme vous en avez besoin.

Par exemple, si vous avez besoin de toutes les valeurs de la 3ème ligne, il vous suffit d'écrire:

Csv csv = new Csv();

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

var allValuesOf3rdRow = csv.Rows[2];

ou lire la 2e cellule de 

var value = csv.Rows[2][1];
0
Andrew