Search code examples
c#csvheadercsvhelper

C# Reading CSV File | with header Row and Comma Separated Values


Below is my CSV Structure (have just taken header row and first data row.

Header 1,Header 2,Header 3,Header 4,Header5
Value 1,"Value2 a,Value 2b","Value3 a,Value 3b",Value 4,Value5

I am able to read CSV, read header row and data Row assuming CSV is having comma separated delimiter.

Few of Code Snippets -

var fileContent = File.ReadAllLines(csvFile.FullName);
List<string> headerValues = null;
List<string> contentAllRows= null;
if (fileContent !=null && fileContent.Any())
{
    headerValues = fileContent.First().Split(separators).ToList();
    headerValues.ForEach(h => h = h.Trim());
    contentAllRows = fileContent.Skip(1).ToList();
}
for (int row = 0; row <= contentAllRows.Count - 1; row++)
{
    var column = contentAllRows[row].Split(separators).ToList();
}

Output of above Code Snippet

headerValues[0] = "Header 1"
headerValues[1] = "Header 2"
headerValues[2] = "Header 3"
headerValues[3] = "Header 4"
headerValues[4] = "Header5"

contentAllRows ="Value 1,\"Value2 a,Value 2b\",\"Value3 a,Value 3b\",Value 4,Value5"

columns[0] = "Value 1"
columns[1] = "\"Value2 a"
columns[2] = "Value 2b\""
columns[3] = "\"Value3 a"
columns[4] = "Value 3b\""
columns[5] = "Value 4"
columns[6] = "Value5"

My Expected Output(against each of above header values) -

columns[0]="Value 1"
columns[1]="Value2 a,Value 2b"
columns[2]="Value3 a,Value 3b"
columns[3]=""
columns[4]="Value5"

Split() seems the problem to me in above case. Do we have an easy solution for the above scenario,I am thinking of having Strongly types objects while reading CSV. Does the above scenario fits in CSV helper module @ https://joshclose.github.io/CsvHelper/2.x/ Any suggestions appreciated.


Solution

  • Since you mention the option of using CsvHelper - it should be fairly straightforward for you use it to map straight to your POCO. Assuming a simple object:

    public class Foo 
    {
        public string Bar1 {get;set;}
        public string Bar2 {get;set;}
        public string Bar3 {get;set;}
        public string Bar4 {get;set;}
        public string Bar5 {get;set;}
    }
    

    Define a class map

    internal sealed class MyCsvMap : ClassMap<Foo>
    {
        public MyCsvMap()
        {
            Map(x => x.Bar1).Name("Header 1");
            Map(x => x.Bar2).Name("Header 2");
            Map(x => x.Bar3).Name("Header 3");
            Map(x => x.Bar4).Name("Header 4");
            Map(x => x.Bar5).Name("Header5");
        }
    }
    

    And then simply

    using (var sr = new StreamReader(csvFile.FullName))
    {
        using (var csvReader = new CsvReader(sr))
        {
            csvReader.Configuration.RegisterClassMap<MyCsvMap>();
            return csvReader.GetRecords<Foo>().ToList();
        }
    }
    

    CsvHelper should automatically deal with your quoted fields - delimiters within double quotes are ignored by the default setting of Configuration.Quote.