web-dev-qa-db-fra.com

Lire toutes les valeurs de CSV dans une liste à l'aide de CsvHelper

J'ai donc lu que je ne devrais pas écrire mon propre lecteur/graveur CSV, j'ai donc essayé d'utiliser la bibliothèque CsvHelper installée via nuget. Le fichier CSV est une image en niveaux de gris, le nombre de lignes correspondant à la hauteur de l’image et le nombre de colonnes à la largeur. Je voudrais lire les valeurs rangées dans un seul List<string> ou List<byte>.

Le code que j'ai jusqu'ici est:

using CsvHelper;

public static List<string> ReadInCSV(string absolutePath)
{
    IEnumerable<string> allValues;

    using (TextReader fileReader = File.OpenText(absolutePath))
    {
        var csv = new CsvReader(fileReader);
        csv.Configuration.HasHeaderRecord = false;
        allValues = csv.GetRecords<string>
    }

    return allValues.ToList<string>();
}

Mais allValues.ToList<string>() jette un:

CsvConfigurationException n'a pas été gérée par le code utilisateur

Une exception de type 'CsvHelper.Configuration.CsvConfigurationException' s'est produite dans CsvHelper.dll mais n'a pas été gérée dans le code utilisateur

Informations complémentaires: les types qui héritent de IEnumerable ne peuvent pas être mappés automatiquement. Avez-vous accidentellement appelé GetRecord ou WriteRecord qui agit sur un seul enregistrement au lieu d'appeler GetRecords ou WriteRecords qui agit sur une liste d'enregistrements?

GetRecords attend probablement ma propre classe personnalisée, mais je veux simplement les valeurs sous forme de type primitif ou de chaîne. En outre, je soupçonne que la ligne entière est convertie en une seule chaîne, au lieu que chaque valeur soit une chaîne distincte.

15
Ayb4btu

Selon le post de @Marc L, vous pouvez essayer ceci:

public static List<string> ReadInCSV(string absolutePath) {
    List<string> result = new List<string>();
    string value;
    using (TextReader fileReader = File.OpenText(absolutePath)) {
        var csv = new CsvReader(fileReader);
        csv.Configuration.HasHeaderRecord = false;
        while (csv.Read()) {
           for(int i=0; csv.TryGetField<string>(i, out value); i++) {
                result.Add(value);
            }
        }
    }
    return result;
}
20
masinger

Si vous n'avez besoin que des valeurs de chaîne pour chaque ligne d'un tableau, vous pouvez utiliser directement l'analyseur.

var parser = new CsvParser( textReader );
while( true )
{
    string[] row = parser.Read();
    if( row == null )
    {
        break;
    }
}

http://joshclose.github.io/CsvHelper/#reading-parsing

Mettre à jour

La version 3 prend en charge la lecture et l'écriture des propriétés IEnumerable.

11
Josh Close

S'il vous plaît essayez ceci. Cela avait fonctionné pour moi.

TextReader reader = File.OpenText(filePath);
            CsvReader csvFile = new CsvReader(reader);
            csvFile.Configuration.HasHeaderRecord = true;
            csvFile.Read();
            var records = csvFile.GetRecords<Server>().ToList();

Le serveur est une classe d'entité. C'est comme ça que j'ai créé.

 public class Server
    {
        private string details_Table0_ProductName;
        public string Details_Table0_ProductName
        {
            get
            {
                return details_Table0_ProductName;
            }
            set
            {
                this.details_Table0_ProductName = value;
            }
        }

        private string details_Table0_Version;
        public string Details_Table0_Version
        {
            get
            {
                return details_Table0_Version;
            }
            set
            {
                this.details_Table0_Version = value;
            }
        }       
    }
3
user3660719

Tu es proche. Ce n'est pas qu'il essaie de convertir le row en une chaîne. CsvHelper essaie de mapper chaque champ de la ligne avec les propriétés du type que vous lui donnez, en utilisant les noms donnés dans une ligne d’en-tête. De plus, il ne comprend pas comment faire cela avec les types IEnumerable (que string implémente), il est donc simplement lancé lorsque le mappage automatique en arrive à ce stade de test du type.


C'est beaucoup de complication pour ce que vous faites. Si votre format de fichier est suffisamment simple, ce qui semble être le vôtre - format de champ bien connu, délimiteurs ni échappés ni guillemets - je ne vois aucune raison pour que vous deviez assumer la surcharge de l'importation d'une bibliothèque. Vous devriez pouvoir énumérer les valeurs au besoin avec System.IO.File.ReadLines() et String.Split().

//pseudo-code...you don't need CsvHelper for this
IEnumerable<string> GetFields(string filepath)
{
  foreach(string row in File.ReadLines(filepath))
  {
    foreach(string field in row.Split(',')) yield return field;
  }
}
2
Marc L.

Le but ici est de lire toutes les lignes de CSV et de les désérialiser en une collection d'objets. Je ne suis pas sûr de savoir pourquoi vous voulez le lire comme une collection de chaînes. ReadAll () générique fonctionnerait probablement le mieux pour vous dans ce cas, comme indiqué précédemment. Cette bibliothèque brille quand vous l'utilisez à cette fin:

using System.Linq;

...
using (var reader = new StreamReader(path))
using (var csv = new CsvReader(reader))
{
    var yourList = csv.GetRecords<YourClass>().ToList();
}

Si vous n'utilisez pas ToList (), il retournera un seul enregistrement à la fois (pour de meilleures performances), veuillez lire https://joshclose.github.io/CsvHelper/examples/reading/enumerate-class-records

0
lead