Getting started
editInstall the package
Add the Meziantou.Framework.Csv package to a project:
dotnet package add Meziantou.Framework.CsvThe 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 callFlushAsync, 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.