Skip to content

CsvHelper

Data & AnalyticsDataC#

What it is

CsvHelper reads and writes CSV files in .NET with class mapping, type conversion and streaming for files larger than memory.

Read records lazily into typed objects or write them out. ClassMap controls the mapping when headers do not match property names.

Installation

dotnet add package CsvHelper

Getting started

The smallest useful thing you can do with it, and what each part means.

Streaming read and write
using var reader = new StreamReader("books.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);

// Lazy — does not load the whole file into memory.
foreach (var book in csv.GetRecords<Book>())
{
    Process(book);
}

using var writer = new StreamWriter("out.csv");
using var w = new CsvWriter(writer, CultureInfo.InvariantCulture);
await w.WriteRecordsAsync(books);
InvariantCulture is not optional — using the machine's culture means a decimal parses differently on a German system, which is a classic production-only bug.

Advanced usage

Where the library earns its place over a simpler alternative.

Mapping and tolerant parsing
public sealed class BookMap : ClassMap<Book>
{
    public BookMap()
    {
        Map(m => m.Title).Name("Book Title", "title");   // accepts either
        Map(m => m.Year).Name("Published").Default(0);
        Map(m => m.Price).TypeConverterOption.NumberStyles(NumberStyles.Currency);
        Map(m => m.Internal).Ignore();
    }
}

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    HeaderValidated = null,      // do not throw on unexpected headers
    MissingFieldFound = null,    // treat missing columns as default
    TrimOptions = TrimOptions.Trim,
};

csv.Context.RegisterClassMap<BookMap>();
Real-world CSVs from other systems are messy. Setting HeaderValidated and MissingFieldFound to null makes the reader tolerant rather than failing on the first irregular file.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Header with name X was not found
The file's header differs. Add alternatives with .Name("a", "b"), or set HeaderValidated to null.
Numbers or dates parse incorrectly on some machines
A culture-dependent conversion. Use InvariantCulture consistently.

Best practices

  • Always specify CultureInfo.InvariantCulture unless you deliberately want locale-specific parsing.
  • Stream with GetRecords rather than ToList for large files.
  • Use ClassMap instead of attributes when the mapping might change per source.
  • Validate rows as you read; a CSV is untrusted input like any other.

Background

Why it exists, and what it was reacting to.

CSV looks trivial and is not: quoting, embedded newlines, delimiters inside fields and encoding all have edge cases. CsvHelper handles them, which is why hand-rolled string.Split parsers keep getting replaced by it.