Getting started

edit

Install the package

Add the Meziantou.Framework.Csv package to a project:

dotnet package add Meziantou.Framework.Csv

The examples of this documentation omit the using directives: they need using Meziantou.Framework.Csv;.

Read a file

Create a CsvReader over a StreamReader, and call ReadRowAsync until it returns null. With HasHeaderRow, the first row gives the names of the columns, and each row gives its values by name:

using var reader = new StreamReader("people.csv");
var csvReader = new CsvReader(reader) { HasHeaderRow = true };

var names = new List<string>();
var totalAge = 0;
while (await csvReader.ReadRowAsync() is { } row)
{
    names.Add(row["Name"]!);
    totalAge += int.Parse(row["Age"]!, CultureInfo.InvariantCulture);
}

Assert.Equal(["Alice", "Bob"], names);
Assert.Equal(55, totalAge);
  • The header row is not returned: the first row ReadRowAsync returns is the first row of data.
  • Values are strings. Parse them with the invariant culture when the file comes from another program, so that the result does not depend on the culture of the machine.
  • The reader does not own the StreamReader: dispose it yourself.

Write a file

WriteRowAsync writes a row. Write the header row first, like any other row:

await using (var writer = new StreamWriter("export.csv"))
{
    var csvWriter = new CsvWriter(writer);
    await csvWriter.WriteRowAsync("Name", "Age");
    await csvWriter.WriteRowAsync("Alice", "30");
} // Disposing the StreamWriter flushes the data to the file

var content = await File.ReadAllTextAsync("export.csv");
Assert.Equal($"Name,Age{Environment.NewLine}Alice,30", content);
  • Rows end with Environment.NewLine; the last row has no line terminator. See Line terminators.
  • The writer does not flush the StreamWriter. Dispose it, or call FlushAsync, before reading the file.

Next steps

  • Reading CSV: headers, separators, quoted values, short rows and positions.
  • Writing CSV: quoting, separators and writing a row value by value.