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 CsvHelperGetting started
The smallest useful thing you can do with it, and what each part means.
csharp
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);Advanced usage
Where the library earns its place over a simpler alternative.
csharp
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>();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.
