This code is based on CsvHelper 15.0.5

Introduction to the

CsvHelper is a tool for reading and writing CSV files. The.net libraries. Extremely fast, flexible and easy to use.

CsvHelper is built on. On TOP of NET Standard 2.0, it can run almost anywhere.

Github address: github.com/joshclose/c…

The module

The module function
CsvHelper Core classes for reading and writing CSV data.
CsvHelper.Configuration Class that configures the read and write behavior of CsvHelper.
CsvHelper.Configuration.Attributes Configure CsvHelper features.
CsvHelper.Expressions Class that generates LINQ expressions.
CsvHelper.TypeConversion A class that converts CSV fields to and from.NET types.

read

The test class

public class Foo
{
    public int ID { get; set; }

    public string Name { get; set; }}Copy the code

CSV file data

ID,Name
1,Tom
2,Jerry
Copy the code

Read all records

using (var reader = new StreamReader("foo.csv"))
{
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        varrecords = csv.GetRecords<Foo>(); }}Copy the code

Blank lines are ignored when reading the CSV file. If blank lines contain Spaces, an error is reported. If it is an Excel edited CSV file, empty lines will become lines containing only delimiters, and an error will be reported.

To read a detailed

using (var reader = new StreamReader("foo.csv"))
{
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        while (csv.Read())
        {
            varrecord = csv.GetRecord<Foo>(); }}}Copy the code

The GetRecords

method yields an IEnumerable

and does not read it all into memory at once unless ToList or ToArray methods are called. So there’s not a lot of need to do that.

Reading a single field

using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.Read();
    csv.ReadHeader();

    while (csv.Read())
    {
        var id = csv.GetField<int> (0);
        var name = csv.GetField<string> ("Name"); }}Copy the code

When reading line by line, you can ignore the header line, but not here.

csv.Read(); The while loop gets the title for the first time, and if it doesn’t get the title for the first time, it’s going to get an error.

csv.ReadHeader(); Csv.getfield

(“Name”) does not find the title.

Use TryGetField to prevent unexpected errors.

csv.TryGetField(0.out int id);
Copy the code

write

Write all records

var records = new List<Foo>
{
    new Foo { ID = 1, Name = "Tom" },
    new Foo { ID = 2, Name = "Jerry"}};using (var writer = new StreamWriter("foo.csv"))
{
    using (var csv = newCsvWriter(writer, CultureInfo.InvariantCulture)) { csv.WriteRecords(records); }}Copy the code

To write a detailed

using (var writer = new StreamWriter("foo.csv"))
{
    using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
    {
        foreach (var record inrecords) { csv.WriteRecord(record); }}}Copy the code

Field by field write

using (var writer = new StreamWriter("foo.csv"))
{
    using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
    {
        csv.WriteHeader<Foo>();
        csv.NextRecord();

        foreach (var record inrecords) { csv.WriteField(record.ID); csv.WriteField(record.Name); csv.NextRecord(); }}}Copy the code

features

Index

The Index feature marks the order of fields.

When you read a file, if there is no title, you can only determine the fields by order.

public class Foo
{
    [Index(0)]
    public int ID { get; set; }

    [Index(1)]
    public string Name { get; set; }}using (var reader = new StreamReader("foo.csv"))
{
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        csv.Configuration.HasHeaderRecord = false;

        varrecords = csv.GetRecords<Foo>().ToList(); }}Copy the code

CSV. Configuration. HasHeaderRecord = false Configuration told CsvReader no title. This line must be added, otherwise the title of the first action will be skipped by default, resulting in a missing line in the final result. If there is a large amount of data, it will be difficult to find this bug.

Files are written in Index order. If you don’t want to write the title, also need to add the CSV Configuration. HasHeaderRecord = false;

Name

If the field Name and column Name do not match, the Name attribute can be used.

public class Foo
{
    [Name("id")]
    public int ID { get; set; }

    [Name("name")]
    public string Name { get; set; }}Copy the code

NameIndex

NameIndex is used to process the same names in CSV files.

public class Foo{... [Name("Name")]
    [NameIndex(0)]
    public string FirstName { get; set; }

    [Name("Name")]
    [NameIndex(1)]
    public string LastName { get; set; }}Copy the code

Ignore

Ignore the field

Optional

If no matching field is found while reading, it is ignored.

public class Foo{... [Optional]public string Remarks { get; set; }}Copy the code

Default

The Default feature specifies a Default value for a field read when it is empty.

The Default feature is valid only when read. Null values are not replaced by Default values when written.

NullValues

public class Foo{... [NullValues("None"."none"."Null"."null")]
    public string None { get; set; }}Copy the code

When the file is read, if the value of a field in the CSV file is null, the value is “” instead of null. After the NullValues feature is marked, if the value of a field in the CSV file is the specified value, the value is null.

If the Default feature is marked at the same time, it does not take effect.

Unfortunately, this feature does not work when writing files. This can cause read and write inconsistency problems.

Constant

The Constant feature specifies a Constant value for the field, which is used for reading and writing regardless of any other mapping or configuration specified.

Format

Format Specifies the string Format to be used for type conversion.

For example, we often specify the format of numeric and time types.

public class Foo{... [Format("0.00")]
    public decimal Amount { get; set; }

    [Format("yyyy-MM-dd HH:mm:ss")]
    public DateTime JoinTime { get; set; }}Copy the code

BooleanTrueValues and BooleanFalseValues

These two features are used to convert bool to display in the specified form.

public class Foo{... [BooleanTrueValues("yes")]
    [BooleanFalseValues("no")]
    public bool Vip { get; set; }}Copy the code

NumberStyles

public class Foo{... [Format("X2")]
    [NumberStyles(NumberStyles.HexNumber)]
    public int Data { get; set; }}Copy the code

Useful is NumberStyles HexNumber and NumberStyles AllowHexSpecifier, the role of the two enumeration. This feature is valid only when read, and does not convert to hexadecimal writes when written. This can lead to inconsistent reads and writes, and you can use the Format feature to specify the write Format.

mapping

If you cannot add features to the classes you want to map, in this case you can use the ClassMap approach.

The effect of using maps is the same as that of using features. The following example implements the functionality of the above feature using properties.

public class Foo2 { public int ID { get; set; } public string Name { get; set; } public decimal Amount { get; set; } public DateTime JoinTime { get; set; } public string Msg { get; set; } public string Msg2 { get; set; } public bool Vip { get; set; } public string Remarks { get; set; } public string None { get; set; } public int Data { get; set; } } public class Foo2Map : ClassMap<Foo2> { public Foo2Map() { Map(m => m.ID).Index(0).Name("id"); Map(m => m.Name).Index(1).Name("name"); The Map (m = > m. mount). TypeConverterOption. The Format (" 0.00 "); Map(m => m.JoinTime).TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss"); Map(m => m.Msg).Default("Hello"); Map(m => m.Msg2).Ignore(); Map(m => m.Vip) .TypeConverterOption.BooleanValues(true, true, new string[] { "yes" }) .TypeConverterOption.BooleanValues(false, true, new string[] { "no" }); Map(m => m.Remarks).Optional(); Map(m => m.None).TypeConverterOption.NullValues("None", "none", "Null", "null"); Map(m => m.Data) .TypeConverterOption.NumberStyles(NumberStyles.HexNumber) .TypeConverterOption.Format("X2"); }}Copy the code

You need to register a map before using it

csv.Configuration.RegisterClassMap<Foo2Map>();
Copy the code

ConvertUsing

ConvertUsing allows type conversions to be implemented using a delegate method.

/ / constant
Map(m => m.Constant).ConvertUsing(row => 3);

// aggregate the two columns together
Map(m => m.Name).ConvertUsing(row => $"{row.GetField<string> ("FirstName")} {row.GetField<string> ("LastName")}");

Map(m => m.Names).ConvertUsing(row => new List<string> { row.GetField<string> ("Name")});Copy the code

configuration

Delimiter

The separator

csv.Configuration.Delimiter = ",";
Copy the code

HasHeaderRecord

This configuration was mentioned earlier whether to use the first line as the title

csv.Configuration.HasHeaderRecord = false;
Copy the code

IgnoreBlankLines

Whether blank lines are ignored. Default is true

csv.Configuration.IgnoreBlankLines = false;
Copy the code

You cannot ignore a line that contains only Spaces or.

AllowComments

Whether comments are allowed, starting with #.

csv.Configuration.AllowComments = true;
Copy the code

Comment

Gets or sets the character used to represent the commented out line. The default is #.

csv.Configuration.Comment = '/';
Copy the code

BadDataFound

Sets up a function that fires when data is incorrect and can be used for logging.

IgnoreQuotes

Gets or sets a value indicating whether quotes should be ignored and treated like any other character when parsing.

The default value is false. If there are quotation marks in the string, there must be three of them “joined together, only one of them will be read in the string”. If there are one of them, the value is ignored.

If true, “is returned as a string.

csv.Configuration.IgnoreQuotes = true;
Copy the code

CsvWriter does not have this property; once the string contains “, it is written as three “joined together.

TrimOptions

Remove space at the beginning and end of fields

csv.Configuration.TrimOptions = TrimOptions.Trim;
Copy the code

PrepareHeaderForMatch

PrepareHeaderForMatch defines the function that matches the property name with the title. Both title and attribute names are run through this function. This feature can be used to remove whitespace from a title or to make a post-case comparison when the title and attribute names are case-insensitive.

csv.Configuration.PrepareHeaderForMatch = (string header, int index) => header.ToLower();
Copy the code