Reading writing dynamic csv causes the first line to drop
lanchapman opened this issue · comments
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 willyield
records.
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.