Search code examples
c#csvtext-parsingfilehelpers

Strongly typed parsing of CSV-files


So after about an hour's worth of pulling my hair in desperation, I decided to follow the advice from, like, everybody in here and not implement my own CSV-parser.

So I went with FileHelpers instead.

But I am having a bit of trouble using it correctly.

My CSV-file looks something like this:

50382018,50319368,eBusiness Manager,IT02,3350_FIB4,IT,2480
50370383,50373053,CRM Manager,IT01,3200_FIB3,xyz,2480
50320067,50341107,"VP, Business Information Officer",IT03,3200_FI89,xyz,2480
50299061,50350088,Project Expert,IT02,8118_FI09,abc,2480

My need for FileHelpers (and, specifically CsvEngine) is in line 3 - notice third column enclosed in quotes since it has an internal comma (which is otherwise used as delimiter).

My code to read the file is this:

var co = new FileHelpers.Options.CsvOptions("Employee", columnDeliminator, 7);
var ce = new CsvEngine(co);

var records = ce.ReadFile(pathToCSVFile);

It works fine - sort of. It correctly parses the lines and recognizes the values with enclosed delimiters.

But.

The return value of the ReadFile()-method is object[]. And the contents of it appears to be some kind of dynamic type.

It looks something like this - where the columns are named "Field_1", "Field_2" etc.

Automatically generated return type

I have created a "data class" intended to hold the parsed lines It looks like this:

public class Employee
{
    public string DepartmentPosition;
    public string ParentDepartmentPosition;
    public string JobTitle;
    public string Role;
    public string Location;
    public string NameLocation;
    public string EmployeeStatus;
}

Is there a way to have FileHelpers' CsvEngine class to return strongly typed data?

If I could just use the "basic" parser of FileHelpers, I could use this code:

var engine = new FileHelperEngine<Employee>();
var records = engine.ReadFile("Input.txt");

Is there a way to have CsvEngine return instances of my "Employee" class? Or do I have to write my own mapping code to support this?


Solution

  • @shamp00 has the correct answer - and I also found it at FileHelper escape delimiter .

    I took my model class and decorated each property on it as suggested:

    (I probably don't need to decorate all properties, but it works for now)

    [DelimitedRecord((","))]
    public class Employee
    {
        [FieldQuoted('"', QuoteMode.OptionalForBoth)]
        public string DepartmentPosition;
        [FieldQuoted('"', QuoteMode.OptionalForBoth)]
        public string ParentDepartmentPosition;
        [FieldQuoted('"', QuoteMode.OptionalForBoth)]
        public string JobTitle;
        [FieldQuoted('"', QuoteMode.OptionalForBoth)]
        public string Role;
        [FieldQuoted('"', QuoteMode.OptionalForBoth)]
        public string Location;
        [FieldQuoted('"', QuoteMode.OptionalForBoth)]
        public string NameLocation;
        [FieldQuoted('"', QuoteMode.OptionalForBoth)]
        public string EmployeeStatus;
    }
    

    Now I just need this code:

    TextReader reader = new StreamReader(contents);
    var engine = new FileHelperEngine<Employee>()
    {
        Options = { IgnoreFirstLines = 1 }
    };
    var myRecords = engine.ReadStream(reader);