ZetCode

C# CSV - read write CSV data

last modified October 10, 2020

C# CSV tutorial shows how to read and write CSV data in C#.

CSV

CSV (Comma Separated Values) is a very popular import and export data format used in spreadsheets and databases. Each line in a CSV file is a data record. Each record consists of one or more fields, separated by commas. While CSV is a very simple data format, there can be many differences, such as different delimiters, new lines, or quoting characters.

In this tutorial, we read and write CSV data with the CsvHelper library.

$ dotnet add package CsvHelper

We need to add the CsvHelper package to our projects.

C# CSV read data by records

In the following example, we read a CSV file by records.

users.csv
FirstName,LastName,Occupation
John,Doe,gardener
Lucy,Smith,teacher
Brian,Bethamy,programmer

We have this users.csv file.

Program.cs
using System;
using System.IO;
using System.Globalization;
using CsvHelper;

namespace CsvReadEx
{
    class Program
    {
        static void Main(string[] args)
        {
            using var streamReader = File.OpenText("users.csv");
            using var csvReader = new CsvReader(streamReader, 
                CultureInfo.CurrentCulture);

            string value;

            while (csvReader.Read())
            {
                for (int i = 0; csvReader.TryGetField<string>(i, out value); i++)
                {
                    Console.Write($"{value} ");
                }

                Console.WriteLine();
            }
        }
    }
}

The Read method advances the reader to the next record. We read the fields of the record with TryGetField.

$ dotnet run
FirstName LastName Occupation 
John Doe gardener 
Lucy Smith teacher 
Brian Bethamy programmer 

This is the output.

C# CSV read data into objects

In the next example, we read the data into objects with GetRecords.

Program.cs
using System;
using System.Globalization;
using System.IO;
using CsvHelper;

namespace CsvReadEx2
{
    class User
    {
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Occupation { get; set; }

        public override string ToString()
        {
            return string.Format("[{0}, {1}, {2}]", FirstName, LastName,
             Occupation);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using var streamReader = File.OpenText("users.csv");
            using var csvReader = new CsvReader(streamReader, 
                CultureInfo.CurrentCulture);

            var users = csvReader.GetRecords<User>();

            foreach (var user in users)
            {
                Console.WriteLine(user);
            }
        }
    }
}

In the example, we define the User class and read the records of the users.csv file into instances of this class. The GetRecords returns the IEnumerable of the given type.

$ dotnet run
[John, Doe, gardener]
[Lucy, Smith, teacher]
[Brian, Bethamy, programmer]

This is the output.

C# CSV configuration

In the following example, we are going to have a CSV file with semicolon separators and a comment. In order to parse such a different "CSV" file, we need to configure the parser.

users.csv
# this is users.csv file

John;Doe;gardener
Lucy;Smith;teacher
Brian;Bethamy;programmer

We have this users.csv file.

Program.cs
using System;
using System.Globalization;
using System.IO;
using CsvHelper;

namespace CsvConfigEx
{
    class Program
    {
        static void Main(string[] args)
        {
            using var streamReader = File.OpenText("users.csv");
            using var csvReader = new CsvReader(streamReader, 
                CultureInfo.CurrentCulture);
            csvReader.Configuration.HasHeaderRecord = false;
            csvReader.Configuration.Comment = '#';
            csvReader.Configuration.AllowComments = true;
            csvReader.Configuration.Delimiter = ";";
            // csvReader.Configuration.IgnoreBlankLines = true;

            while (csvReader.Read())
            {
                var firstName = csvReader.GetField(0);
                var lastName = csvReader.GetField(1);
                var occupation = csvReader.GetField(2);

                Console.WriteLine($"{firstName} {lastName} is {occupation}");
            }
        }
    }
}

The reader is configured with the Configuration property.

csvReader.Configuration.HasHeaderRecord = false;

We tell the reader that there is no header. , the comment character is #,

csvReader.Configuration.Comment = '#';
csvReader.Configuration.AllowComments = true;

We allow comments in the file and set the comment's character. (Actually, we don't have to set the comment character because by default the # is used.)

csvReader.Configuration.Delimiter = ";";
// csvReader.Configuration.IgnoreBlankLines = true;

We set the delimiter to semicolon character. The blank lines are ignored by default.

$ dotnet run
John Doe is gardener
Lucy Smith is teacher
Brian Bethamy is programmer

This is the output.

C# CSV write data by records

In the following example, we write CSV data by records.

Program.cs
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Collections.Generic;
using CsvHelper;

namespace CsvWriteEx
{
    class User
    {
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Occupation { get; set; }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            var users = new List<User>
            {
                new User { FirstName = "John", LastName = "Doe", 
                    Occupation = "gardener" },
                new User { FirstName = "Lucy", LastName = "Smith", 
                    Occupation = "teacher" },
                new User { FirstName = "Brian", LastName = "Bethamy", 
                    Occupation = "programmer" },
            };

            using var mem = new MemoryStream();
            using var writer = new StreamWriter(mem);
            using var csvWriter = new CsvWriter(writer, CultureInfo.CurrentCulture);

            csvWriter.WriteField("FirstName");
            csvWriter.WriteField("LastName");
            csvWriter.WriteField("Occupation");
            csvWriter.NextRecord();

            foreach (var user in users)
            {
                csvWriter.WriteField(user.FirstName);
                csvWriter.WriteField(user.LastName);
                csvWriter.WriteField(user.Occupation);
                csvWriter.NextRecord();
            }

            writer.Flush();
            var result = Encoding.UTF8.GetString(mem.ToArray());
            Console.WriteLine(result);
        }
    }
}

In the example, we write CSV data into memory and then to the console.

csvWriter.WriteField("FirstName");
csvWriter.WriteField("LastName");
csvWriter.WriteField("Occupation");
csvWriter.NextRecord();

First, we write the header. The NextRecord method adds a newline.

foreach (var user in users)
{
    csvWriter.WriteField(user.FirstName);
    csvWriter.WriteField(user.LastName);
    csvWriter.WriteField(user.Occupation);
    csvWriter.NextRecord();
}

The WriteField writes the field to the CSV file. A new record is started with NextRecord.

writer.Flush();

To actually write the data, we need to call Flush.

var result = Encoding.UTF8.GetString(mem.ToArray());
Console.WriteLine(result);

We write the data from the memory to the console.

$ dotnet run
FirstName,LastName,Occupation
John,Doe,gardener
Lucy,Smith,teacher
Brian,Bethamy,programmer

This is the output.

C# CSV write data with WriteRecords

In the following example, we write all the records in one shot with WriteRecords.

Program.cs
using System;
using System.Globalization;
using System.IO;
using System.Collections.Generic;
using CsvHelper;

namespace CsvWriteEx2
{
    class User
    {
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Occupation { get; set; }
    }

    public class Program
    {

        static void Main(string[] args)
        {
            var users = new List<User> 
            {
                new User { FirstName = "John", LastName = "Doe", 
                    Occupation = "gardener" },
                new User { FirstName = "Lucy", LastName = "Smith", 
                    Occupation = "teacher" },
                new User { FirstName = "Brian", LastName = "Bethamy", 
                    Occupation = "programmer" },
            };

            using var writer = new StreamWriter(Console.OpenStandardOutput());
            using var csvWriter = new CsvWriter(writer, CultureInfo.CurrentCulture);

            csvWriter.WriteHeader<User>();
            csvWriter.NextRecord(); // adds new line after header
            csvWriter.WriteRecords(users);

            writer.Flush();
        }
    }
}

In the example, we write the data from the list of user objects into console. The WriteHeader writes the header record from the given members.

In this tutorial, we have read and written CSV data in C# with the CsvHelper library.

Visit C# tutorial or list all C# tutorials.