This is 2015, and we shouldn’t be working with CSV files any more, but reality is, they are the most commonly used file exchange method around.
As a C# developer, we can make use of standard String and Array classes and we can read/write CSV files. However, there is a maintenance issue, imagine you have a CSV file with 15+ columns, and now you have been asked to update the code with additional columns. Updating index based columns with additional column is a tedious and error prone task.
There is a better way, use FileHelpers. This is a free and Open Source C# library to handle CSV files related operations.
This can be installed as NuGet package within the project.
I am going to assume that the CSV file has got only 2 columns as following :
1.Name
2.Description
And the description column could have double quotes ” and a comma can be included within the double quotes.
Step 1 : Create a simple C# class for the CSV file and add field attributes using FileHelpers as following:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using FileHelpers; | |
namespace MyProject | |
{ | |
[DelimitedRecord(",")] | |
[IgnoreEmptyLines()] | |
[IgnoreFirst()] | |
public class MyProduct | |
{ | |
//Name | |
public string Name{ get; set; } | |
//Description, this attribute will handle the double quotes issue | |
[FieldQuoted('"', QuoteMode.OptionalForBoth)] | |
public string Description{ get; set; } | |
} | |
} |
Step 2 : The Second step would be to read the flat CSV file into this object.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void ReadCSVFile(string fileName) | |
{ | |
try | |
{ | |
//file location, better to get it from configuration | |
string fileName = "C:\\temp\\MyProducts.csv"; | |
//create a CSV engine using FileHelpers for your CSV file | |
var engine = new FileHelperEngine(typeof(MyProduct)); | |
//read the CSV file into your object Arrary | |
var products = (MyProduct[])engine.ReadFile(fileName); | |
if (products.Any()) | |
{ | |
//process your records as per your requirements | |
foreach (var product in products) | |
{ | |
//add it to your database, filter them etc | |
string name = product.Name | |
string description = product.Description | |
} | |
} | |
} | |
catch (Exception ex) | |
{ | |
LogException(ex) | |
} | |
} |
And that’s it. In case you have to add more columns or remove any column, all you have to is to update the ‘MyProduct.cs’ class file and update the associated strongly typed code.
Now lets assume the opposite, that you have a some sort of data in the database or CMS or external data source and you want to write that into CSV file.
Using the same ‘MyProduct.cs’ class above, the write method will be as following:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void WriteCSVFile(List<SomeDataSource> dataSource) | |
{ | |
try | |
{ | |
//filehelper object | |
FileHelperEngine engine = new FileHelperEngine(typeof(MyProdcuts)); | |
//csv object | |
List<MyProduct> csv = new List<MyProduct>(); | |
//convert any datasource to csv based object | |
foreach (var item in dataSource) | |
{ | |
MyProduct temp = new MyProduct(); | |
temp.Name = item.Name; | |
temp.Description = item.Description | |
csv.Add(temp); | |
} | |
//give file a name and header text | |
string filename = "MyProducts.csv"; | |
engine.HeaderText = "Name,Description"; | |
//save file locally | |
engine.WriteFile(Server.MapPath(filename),csv); | |
} | |
catch (Exception ex) | |
{ | |
LogException(ex); | |
} | |
} |
Whoooa! that’s it.
Thanks!
Hi there just a little optimization:
var engine = new FileHelperEngine();
var products = engine.ReadFile(fileName);
And the new page of the library that is on http://www.filehelpers.net
Cheers
Hi Naveed,
what about if i need to read from that CSV, make some webservices calls to gather more information, after I get that information I need to be able to add new columns and populate them with that new informaiton to that same CSV file. Basically how can I update using the same csv file I am reading from?
Hi Felipe,
Sorry for late reply. You actually have 2 different CSV file structures, so you would need 2 different classes and 2 different set of files, one for reading and one for writing. You can read using your ‘pre-processing’ class, process your data via web services and you can write using your ‘post-processing’ class with additional columns/properties name.
How about this:
private void WriteFile(string fileName,List listData) where T : class
{
try
{
//filehelper object
FileHelperEngine engine = new FileHelperEngine();
engine.WriteFile(fileName, listData.ToArray());
}
catch (Exception ex)
{
LogException(ex);
}
}
Thanks a lot, Naveed! It was really helpful for me.
Name,Description
Test1, “Test, Data”
this structure fails, because filehelper using the delimiter string comma splits first. that’s y your example fails