Reading writing dynamic csv causes the first line to drop
When reading and writing a CSV file as a dynamic object, if headers are enabled, the first line after the header is dropped.
using var readstream = new StreamReader("input.csv");
using var writestream = new StringWriter();
using var csvreader = new CsvReader(readstream, CultureInfo.InvariantCulture);
using var csvwriter = new CsvWriter(writestream, CultureInfo.InvariantCulture);
var records = csvreader.GetRecords<dynamic>();
csvwriter.WriteRecords(records);
File.WriteAllText("output.csv", writestream.ToString());
input.csv
t1,t2,t3
1,2,3
4,5,6
7,8,9
The files input.csv and output.csv should be the same.
The output.csv shows
t1,t2,t3
4,5,6
7,8,9
This is an issue with how CsvReader.GetRecords<T>() works. https://joshclose.github.io/CsvHelper/getting-started/
The
GetRecords<T>method will return anIEnumerable<T>that willyieldrecords.
If you take a look at the internal private bool WriteHeader<T>(IEnumerable<T> records), you will see that if it knows the class, it can WriteHeader(recordType). If, however, it isn't a standard class, such as dynamic, it must read the first record with WriteHeader(records.FirstOrDefault()). That FirstOrDefault(), unfortunately calls the first yielded result from CsvReader and there is no way to go back to the beginning of the IEnumerable<dynamic>.
private bool WriteHeader<T>(IEnumerable<T> records)
{
if (!hasHeaderRecord || hasHeaderBeenWritten)
{
return false;
}
var recordType = typeof(T);
var isPrimitive = recordType.GetTypeInfo().IsPrimitive;
if (!isPrimitive && recordType != typeof(object))
{
WriteHeader(recordType);
return hasHeaderBeenWritten;
}
return WriteHeader(records.FirstOrDefault());
}
You can call ToList() on csvreader.GetRecords<dynamic>() and this will solve the issue. It does, however, mean pulling the whole list into memory first before writing it.
using (var readstream = new StringReader("t1,t2,t3\n1,2,3\n4,5,6\n7,8,9"))
using (var csvreader = new CsvReader(readstream, CultureInfo.InvariantCulture))
using (var csvwriter = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
{
var records = csvreader.GetRecords<dynamic>().ToList();
csvwriter.WriteRecords(records);
}
Unfortunately, I don't think there is a good way for @JoshClose to fix this issue without making major and likely unwelcome changes to how CsvReader works.