Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing a csv file, reading and writing with dynamic mapping

Tags:

c#

.net

csvhelper

Assume I have a large csv file that I'd like to read, modify and write back. Perhaps I want to change a field separator from comma to tab. Perhaps I want to change the quotation character from ' to ". Or may be I want to add a plus sign to each value in the first column. Since the file is large, I do not want to load it in memory all at once, I'd like to read it record by record.

So I write a code like this:

var inPath = @"infile.txt";
var outPath = @"outfile.txt";

CsvConfiguration readCf = GetReadConfiguration();
CsvConfiguration writeCf = GetWriteConfiguration();

using (var streamin = new FileStream(inPath, FileMode.Open))
using (var streamReader = new StreamReader(streamin))
{
    using (var csvReader = new CsvReader(streamReader, readCf))
    using (var csvWriter = new CsvWriter(new StreamWriter(outPath), writeCf))
    {
        while (csvReader.Read())
        {
            var currentRecord = csvReader.GetRecord<dynamic>();
            UpdateRecord(currentRecord);
            csvWriter.WriteRecord(currentRecord);
        }
    }
}

This fails at run time with the following error:

Types that inherit IEnumerable cannot be auto mapped. Did you accidentally call GetRecord or WriteRecord which acts on a single record instead of calling GetRecords or WriteRecords which acts on a list of records?

Note, that nothing interesting happens in UpdateRecord, in fact this line above can be completely commented out.

What happens is that GetRecord returns an ExpandoObject and then WriteRecord chokes on this object.

What is the best way to make this work?

Update Just so it's clear: I fully realize that I'm getting this error is because CSVHelper does not support ExpandoObjects for WriteRecord call. I'm looking for suggestions, for easiest way to make this work.

like image 771
Andrew Savinykh Avatar asked Dec 02 '16 22:12

Andrew Savinykh


Video Answer


1 Answers

It appears that ability to write ExpandoObject is added in this commit.

Note that this is not in the latest nuget release (2.16.3 as of the time of writing) but for the next 3.x release. If it's an option for you get latest beta from github and use that.

If you do, note that you will have to call NextRecord after each WriteRecord. In 2.16.3 CVSHelper would call it for you, so it's a bit of a breaking API change

like image 155
Andrew Savinykh Avatar answered Sep 28 '22 18:09

Andrew Savinykh