CsvHaibara
Latest version: 2.0.0
A lightweight and versatile .NET library for reading and writing CSV files. It is designed for efficient asynchronous processing, streaming large datasets with minimal memory overhead, and providing consistent serialization and deserialization behavior.
Install
Package Manage Console
Install-Package CsvHaibara
.NET CLI
dotnet add package CsvHaibara
Class StreamIn (used in reading file)
StreamIn streamIn = new(ICsvHaibara csvHaibara, string path);
StreamIn streamIn = new(ICsvHaibara csvHaibara, Stream stream);
Class StreamOut (used in writing file)
StreamOut streamOut = new(ICsvHaibara csvHaibara, string path);
StreamOut streamOut = new(ICsvHaibara csvHaibara, Stream stream);
Serialize
class Person
{
public string Name { get; set; }
public bool Gender { get; set; }
public int Age { get; set; }
}
using CsvHaibaraNt.Core;
string path = "person.csv";
var persons = new List<Person>
{
new Person { Name = "Alice", Gender = false, Age = 20 },
new Person { Name = "Adam", Gender = true, Age = 25 }
};
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
using (StreamOut streamOut = new(csvHaibara, path))
await csvHaibara.SerializeAsync<Person>(streamOut, persons, true);
}
Deserialize to generic objects
class Person
{
public string Name { get; set; }
public bool Gender { get; set; }
public int Age { get; set; }
}
using CsvHaibaraNt.Core;
string path = "person.csv";
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
await using (StreamIn streamIn = new(csvHaibara, path))
{
var persons = csvHaibara.DeserializeAsync<Person>(streamIn, true);
await foreach (Person p in persons)
{
// Do something
}
}
}
Deserialize to dynamic objects
- The objects properties will be named Property_0, Property_1 , and so on.
- The data type of all objects' properties will be object by default.
using CsvHaibaraNt.Core;
string path = "person.csv";
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
await using (StreamIn streamIn = new(csvHaibara, path))
{
var objs = csvHaibara.DeserializeAsync(streamIn, true);
await foreach (dynamic o in objs)
{
// Do something
}
}
}
Deserialize to anonymous objects
using CsvHaibaraNt.Core;
string path = "person.csv";
var objDefinition = new
{
Name = string.Empty,
Gender = default(bool),
Age = default(int)
};
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
await using (StreamIn streamIn = new(csvHaibara, path))
{
var objs = csvHaibara.DeserializeAsync(objDefinition, streamIn, true);
await foreach (dynamic d in objs)
{
// Do something
}
}
}
Ignore error lines
By default, when reading a CSV file, CsvHaibara will stop when facing the first invalid line (like wrong data, etc..). In case you want to ignore any wrong line and read until the end of the file, set parameter ignoreInvalidLines to be true.
Ignore columns
- All ignored properties will be left as their default value, e.g. 0 for int, false for bool.
- When writing file, all ignored columns disappear in output file.
- When reading file, all ignored columns MUST NOT APPEAR in input file.
class Person
{
public string Name { get; set; }
public bool Gender { get; set; }
public int Age { get; set; }
}
using CsvHaibaraNt.Core;
string path = "person.csv";
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.Ignore<Person>(m => m.Gender, m => m.Age);
await using (StreamIn streamIn = new(csvHaibara, path))
{
var persons = csvHaibara.DeserializeAsync<Person>(streamIn, true);
await foreach (Person p in person)
{
// Do something
}
}
}
Include all columns
Later on, when you want to take all ignored columns again.
using CsvHaibaraNt.Core;
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.IncludeAll<Person>();
}
Rest Columns
Q: If I have a class in which the last property is a list of values
such that the count of this list vary for each row. Can CsvHaibara
map from the input file to that class as expected?
A: Yes, for sure. Assume that we have the input file with the content:
1,1035,@good,@bad
2,5716,@medium,@bad,@good,@good
3,701,@bad,@good,@medium
In code, we can create the mapping class:
public class Sample
{
public int Id { get; set; }
public int TakenUserId { get; set; }
public string[] Results { get; set; }
}
Then we can do as following, using method RestColumns:
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.RestColumns<Sample, string>(m => m.HashTags);
await using (StreamIn streamIn = new(csvHaibara, path))
{
var samples = csvHaibara.DeserializeAsync<Sample>(streamIn);
await foreach (Sample sp in samples)
{
// Do something
}
}
}
Note:
- The data type of element in RestColumns property must be primitive types.
- A class/struct/record can have at most one RestColumns property. In case
multiple fields are set like that, the last wins.
- If a class/struct/record contains RestColumns property, you cannot
ignore any column. These features exclude mutual.
Setting Delimiter
Default Delimiter is comma.
using CsvHaibaraNt.Core;
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.Delimiter = ';';
}
Setting Encoding
- Default Encoding is UTF8.
- Changing Encoding must be done before using StreamIn or StreamOut.
using CsvHaibaraNt.Core;
string path = "person.csv";
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.Encoding = Encoding.ASCII;
await using (StreamIn streamIn = new(csvHaibara, path))
{
}
}
Setting Escape
Default Escape is double quote.
using CsvHaibaraNt.Core;
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.Escape = '^';
}
Setting CultureInfo
Default CultureInfo is CurrentCulture.
using CsvHaibaraNt.Core;
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.CultureInfo = CultureInfo.InvariantCulture;
}
Setting NullStringValue
- To distinguish null string from empty string.
- By default, missing value of string field is treated at an empty string.
- Therefore, in order to get null value, you have to indicate a special string as null value. If any string field gets this value, it is considered as null value. Make sure this is the unique string to avoid unexpected results.
- Default NullStringValue is null.
using CsvHaibaraNt.Core;
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.NullStringValue = "None";
}
Boolean Converter
Instead of traditional values true/false. You are able to use other custom values like yes/no, 1/0.
using CsvHaibaraNt.CoreModels;
public class Person
{
public string Name { get; set; }
[BooleanFalseValue("0")]
[BooleanTrueValue("1")]
public bool Gender { get; set; }
public int Age { get; set; }
}
Setting column header
Custom column header will be display in output file.
using CsvHaibaraNt.CoreModels;
public class Person
{
[ColumnHeader("Given Name")]
public string FirstName { get; set; }
[ColumnHeader("Family Name")]
public string LastName { get; set; }
}
Example: output file
Given Name,Family Name
Fina,Hugg
Dan,Rail
DateTime Format Printout
- Declare the exact format DateTime value that you want to print out.
- This attribute is only useful in writing file and for DateTime type.
using CsvHaibaraNt.CoreModels;
public class Person
{
public string Name { get; set; }
[DateTimeFormat("yyyy-MM-dd")]
public DateTime EntryDate { get; set; }
}
Assign object as default value if all fields are null or missing values
- Once this method is called with parameter true, then when reading file, if all fields are null or missing values, that object will be assigned as null class object or default value struct object or its default value if any.
- The default treatment is corresponding with parameter false, that object is left as it is.
public class Person
{
public string Name { get; set; }
public Address Address1 { get; set; }
public int Age { get; set; }
public Address Address2 { get; set; }
}
public class Address
{
public string City { get; set; }
public string Country { get; set; }
}
using CsvHaibaraNt.Core;
using (ICsvHaibara csvHaibara = CsvHaibaraConfiguration.GetCsvHaibara())
{
csvHaibara.SetDefaultIfAllFieldsNullOrMissing<Address>(true);
}
Example of default values in multiple cases.
public class Person
{
public string FirstName { get; set; } //default is null
public string LastName { get; set; } = "name"; //default is "name"
public Address Address1 { get; set; } //default is null (Address is a class)
public int Age { get; set; } //default is 0
public Address Address2 { get; set; } = new(); //default is new Address()
public int Points { get; set; } = 100; //default is 100
}
Exception
Exeption only occurs in these cases:
- Open input/output file failed
- There is conflict between Delimiter and Escape
Ex: Delimiter and Escape are both comma
- There is conflict between Delimiter and CultureInfo's decimal point
Ex: Delimiter and decimal point are both comma
- There is conflict between Escape and CultureInfo's decimal point
Ex: Escape and decimal point are both comma
- When writing file, list of objects is null
- When number of columns in any data row (including header row) is greater
than number of properties of that type (generic and anonymous types)
- Cast value failed
Ex:
public class Person
{
public string Name { get; set; }
public bool Gender { get; set; }
public int Age { get; set; }
}
Input file:
Mary, false, c
Then it should be failed when parsing column Age
FAQs
Q: How does CsvHaibara handle case when there are
some missing fields in input file?
A: If any missing field occurs, the corresponding
property will be set as its default value.
Ex:
public int Count_1 { get; set; } //default value is 0
public int Count_2 { get; set; } = 100; //default value is 100
Q: How does CsvHaibara print null object?
A: Its properties will be considered as missing values.
- For string type, it will be printed as null. If you already
set another value representing for NullStringValue, then that
value will be used.
- For other types, they will be printed as missing value.