Home c# Reading a CSV file with CsvHelper

Reading a CSV file with CsvHelper

Author

Date

Category

Hello everyone, I’m a beginner. I want to get data from a CSV file – Id and Name fields, but when I run the reading method, I get only 100 lines of an incomprehensible type: “CsvHelper.CsvReaderd__87`1 [Program + Product]”. I don’t know how to get data from CSV, I also cannot understand where the error is.

Although the documentation says that having the same property names and CSV headers, there is no need to write additional configurations. However, I get the above result. CSV names are the same as classes. Link to documentation: https://joshclose.github.io/CsvHelper/getting-started/

{
    using (var reader = new StreamReader ("C: \\ Users \\ Saint \\ Desktop \\ TaskRetail \\ file.csv", Encoding.UTF8))
    using (var csv = new CsvReader (reader, CultureInfo.InvariantCulture))
    {
      var records = csv.GetRecords & lt; Product & gt; ();
      Console.WriteLine ($ "{records}");
    }
  }

CSV is created without problems, there are two columns with Id and Name
with filled lines, total lines 100:

The method itself for creating csv with fields Id and Name:

using (var writer = new StreamWriter ("C: \\ Users \\ Saint \\ Desktop \\ TaskRetail \ \ file.csv ", false, Encoding.UTF8))
  using (var csv = new CsvWriter (writer, CultureInfo.InvariantCulture))
  {
    csv.WriteRecords (products);
  }

Here’s all the code just in case:

using CsvHelper;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;
public class Program
{
  public class Product
  {
    public int Id {get; set; }
    public string Name {get; set; }
    public Product (int id, string name)
    {
      Id = id;
      Name = name;
    }
  }
  public const string PathToDoc = "C: /Users/Saint/Desktop/TaskRetail/yml.xml";
  public static void Main (string [] args)
  {
    string url = "https://www.googleapis.com/drive/v3/files/1sSR9kWifwjIP5qFWcyxGCxN0-MoEd_oo?alt=media&key=AIzaSyBsW_sj1GCItGBK0vl8hr9zu1oI1vTI1Me1I1vTI1Me1I1;
    string savePath = @ "C: \ Users \ Saint \ Desktop \ TaskRetail \ yml.xml";
    WebClient client = new WebClient ();
    client.DownloadFile (url, savePath);
    Research ();
  }
  public static void Research ()
  {
    Encoding.RegisterProvider (CodePagesEncodingProvider.Instance);
    var document = new XmlDocument ();
    document.Load (PathToDoc);
    var xmlDoc = document.SelectNodes ("/ yml_catalog / shop / offers / offer");
    var count = xmlDoc.Count;
    var products = new List & lt; Product & gt; ();
    Console.WriteLine ($ "Offers count: {count}");
    for (var i = 0; i & lt; count; i ++)
    {
      var element = xmlDoc.Item (i);
      var id = int.Parse (element.Attributes.GetNamedItem ("id"). Value);
      var name = element.SelectSingleNode ("name"). InnerText;
      var product = new Product (id, name);
      //Console.WriteLine($"Id: {id}, name: {name} ");
      products.Add (product);
      using (var writer = new StreamWriter ("C: \\ Users \\ Saint \\ Desktop \\ TaskRetail \\ file.csv", false, Encoding.UTF8))
      using (var csv = new CsvWriter (writer, CultureInfo.InvariantCulture))
      {
        csv.WriteRecords (products);
      }
  var config = new CsvConfiguration (CultureInfo.InvariantCulture) {Delimiter = ";" };
  using (var reader = new StreamReader ("C: \\ Users \\ Saint \\ Desktop \\ TaskRetail \\ file.csv", Encoding.UTF8))
  using (var csv = new CsvReader (reader, config))
  {
    var records = csv.GetRecords & lt; Product & gt; ();
    foreach (var record in records)
    { 
Console.WriteLine ($ "{record.Id} {record.Name}");
    }
  }
}

}


Answer 1, authority 100%

You are trying to display a collection of records at once like this:

Console.WriteLine ($ "{records}");

A collection of records cannot be displayed just like that. More precisely, you can, but the basic implementation of ToString () will be called, which displays just the name of the type and so on. To display each entry in turn on a new line, you must iterate over the collection, for example, through the foreach :

loop

foreach (var record in records)
  Console.WriteLine (record);

However, your Product class also does not override the ToString () method, so you will see the base implementation again. How to reload ToString () for your type is described here .

Also, instead of reloading ToString () , you can simply output the individual fields:

foreach (var record in records)
  Console.WriteLine ($ "{record.Id} {record.Name}");

UPD:

The error Header with name 'id' [0] was not found.Header with name 'name' [0] was not found occurs because the CsvHelper writes and reads data.

By default, when writing, it writes all the class fields (Id and Name ) to the file, and when reading it, it writes out the constructor that accepts arguments with names from the header column (the same Id and Name ). There is no such constructor, since all names in the constructor are with a lowercase letter, so it throws an error. To solve this problem I have 2 options.

First option: prepare headings by converting them to lowercase. To do this, you need the following config:

var config = new CsvConfiguration (CultureInfo.InvariantCulture)
{
  PrepareHeaderForMatch = (args) = & gt; args.Header.ToLower ()
};

The second option is to allow assigning fields without a constructor. To do this, in the Person class, you need to make a public empty constructor and pass the following config to csvReader :

var config = new CsvConfiguration (CultureInfo.InvariantCulture)
{
  ShouldUseConstructorParameters = type = & gt; false
};

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions