C#

How to Read Data From a CSV File in C#

Reading from a CSV file in C# is a common operation. In this article, we are going to show how to easily read data from a CSV file in C# using the CSVHelper NuGet package.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

Read Data From a CSV File With Headers

In a previous article, we had already shown how to write to a CSV file.  That said, we strongly recommend reading that article first because the reading operation is very similar to writing, and we won’t explain the same concepts here.

So again, we are going to create a new console project and will try reading the same CSV file, that we created in the previous article.

Reading from it is very similar to writing to it:

using (var reader = new StreamReader("filePersons.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    var records = csv.GetRecords<Person>();
}

As we can compare with writing to a CSV file, we use a StreamReader instead of a StreamWriter, and use the CsvReader instead of the CsvWriter. We then map the data in the CSV file to our own Person class:

public class Person
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public bool IsLiving { get; set; }
    public DateTime DateOfBirth { get; set; }
}

Reading dates is also very straightforward – it will automatically deduce its format from the CSV file.

Read Data From a CSV File Without Headers

What happens when there are no headers present? How can we tell which column needs to be mapped to which property of our Person class? 

Well, we can do that by specifying that headers are not present:

var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    HasHeaderRecord = false,
};

using (var reader = new StreamReader("filePersons.csv"))
using (var csv = new CsvReader(reader, configuration))
{
    var records = csv.GetRecords<Person>();
}

There are two methods for mapping columns to properties in our class.

The first is to use annotations to specify the index:

public class Person
{
    [Index(0)]
    public int Id { get; set; }
    [Index(1)]
    public string? Name { get; set; }
    [Index(2)]
    public bool IsLiving { get; set; }
}

Even in case the fields are all in order, like in this example, we can’t rely on that fact, so still, the index attributes need to be present.

The second, and more powerful way, is to use a mapping:

public class PersonMap : ClassMap<Person>
{
    public PersonMap()
    {
        Map(p => p.Id).Index(0); 
        Map(p => p.Name).Index(1);
        Map(p => p.IsLiving).Index(2);
    }
}

We can create a mapping by deriving from ClassMap<T>, which is in the CsvHelper.Configuration namespace. By using a mapping, we don’t need to annotate the fields in our Person class. This can be handy, when said class is outside of our control and when we can’t make changes to it. In our mapping code, we map the first index (index 0) to the Id field, the second index to the Name field etc.

To use this map, we need to register it in the context:

using (var reader = new StreamReader("filePersons.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.Context.RegisterClassMap<PersonMap>();
    var records = csv.GetRecords<Person>();
}

Comments and Delimiters

The CSV file can contain comments and can use a different delimiter than the comma. Of course, this can be specified in the CsvConfiguration  as well:

var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    Delimiter = ";",
    Comment = '%'
};

The default delimiter is , while the default comment is #. When using a different value, we can thus specify it in the configuration, which we pass into the CsvReader.

Conclusion

In this article, we’ve seen how easy it is to read from a CSV file using CSVHelper. We also saw that it is easy to read when there are no headers present, or to use a different delimiter or comment.

Code Maze

Share
Published by
Code Maze

Recent Posts

HttpClient vs RestSharp – Which One to Use in .NET

HttpClient and RestSharp are HTTP Client libraries that we can use to consume APIs. Working…

Updated Date Jul 7, 2022

Testing Repository Pattern Using Entity Framework

Unit Testing is extremely important for creating robust software. It's very simple in principle but…

Updated Date Jul 6, 2022

Shell Sort in C#

Have you ever needed to sort a list of items, but didn't want to use…

Updated Date Jul 5, 2022

How to Resolve Instances With ASP.NET Core DI

In ASP.NET Core dependency injection, we usually register injectable dependencies at the start of our…

Jul 4, 2022

Ranges and Indices in C#

In this article, we are going to learn more about ranges and indices in C#,…

Updated Date Jul 2, 2022

Code Maze Weekly #128

Issue #128 of the Code Maze weekly. Check out what's new this week and enjoy…

Updated Date Jul 1, 2022