kjv
kjv

Reputation: 11327

How can I write headers with spaces using CsvHelper?

I am using the CsvHelper library to generate a CSV file from an IEnumerable<Person>, where Person is a basic class.

public class Person
{
    public string DisplayName { get; set; }
    public int Age { get; set; }
}

I need to write quoted headers, i.e. instead of "DisplayName", the column in the resulting file should be "Display Name".

How can I do this?

Upvotes: 7

Views: 5289

Answers (4)

Ibrahim
Ibrahim

Reputation: 1

A generic implementation of the top rated answer :

public class TempCSVFile<T, F> where T : class where F : ClassMap
{
    public byte[] CreateTempFile(List<T> data)
    {
        using (var mem = new MemoryStream())
        using (var writer = new StreamWriter(mem))
        using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture))
        {
            csvWriter.Context.RegisterClassMap<F>();
            csvWriter.WriteRecords(data);   
            csvWriter.Flush();
            return mem.ToArray();
        }
    }
}

Also you can use AutoMap if you don't want to change all the properties

public class Person
{
    public string DisplayName { get; set; }
    public int Age { get; set; }
}

public sealed class PersonMap : ClassMap<Person>
{
    public PersonMap()
    {
        Map(m => m.DisplayName).Name("Display Name");
        AutoMap(CultureInfo.InvariantCulture);
    }
}

Upvotes: 0

AndrewA
AndrewA

Reputation: 61

Configure the header names with Attributes

Example with Person:

using CsvHelper.Configuration.Attributes;

public class Person
{
    [Name("Display Name")]
    public string DisplayName { get; set; }
    [Name("Age")]
    public int Age { get; set; }
}

Another Example:

using CsvHelper.Configuration.Attributes;

public class CompanyExportData
{
    [Name("Company Code")]
    public string DisplayName { get; set; } = "Store";
    [Name("Employee Number")]
    public string EmployeeNumber { get; set; }
    [Name("Primary Email Address")]
    public string PrimaryEmailAddress { get; set; }
}

From the CSVHelper docs on how to use Attributes

Upvotes: 0

Josh Close
Josh Close

Reputation: 23403

Create a ClassMap.

void Main()
{
    using (var stream = new MemoryStream())
    using (var writer = new StreamWriter(stream))
    using (var reader = new StreamReader(stream))
    using (var csv = new CsvWriter(writer))
    {
        var records = new List<Person>
        {
            new Test { DisplayName = "one", Age = 1},
            new Test { DisplayName = "two", Age = 2 },
        };
        
        csv.Configuration.RegisterClassMap<PersonMap>();
        csv.WriteRecords(records);
        
        writer.Flush();
        stream.Position = 0;
        
        Console.WriteLine(reader.ReadToEnd());
    }
}

public class Person
{
    public string DisplayName { get; set; }
    public int Age { get; set; }
}

public sealed class PersonMap : ClassMap<Person>
{
    public PersonMap()
    {
        Map(m => m.DisplayName).Name("Display Name");
        Map(m => m.Age);
    }
}

Output:

Display Name,Age
one,1
two,2

Upvotes: 9

Johny Skovdal
Johny Skovdal

Reputation: 2104

I had no headers with workaround, so I did this quick workaround instead:

foreach (var property in typeof(MyCsvClass).GetProperties())
{
  csvWriter.WriteField(property.Name.Replace('_', ' '));
}
csvWriter.NextRecord();
csvWriter.WriteRecords(models);

This takes the property names and replace underscore with space, so I could just name the properties with underscores instead of spaces, and it mapped correctly.

It requires, however, that you use the HasHeaderRecord = false option on the CsvWriter.

Upvotes: 1

Related Questions