Click here to Skip to main content
Click here to Skip to main content

C# CSV Reader and Writer

By , 22 Jun 2010
 

Introduction

I have lost count of the number of projects I have worked on that required me to write data in a CSV format and present it to the user for download. On a recent project, I decided that it would be a good idea to implement some classes that would simplify the process of reading from and writing to a CSV file.

I had a scan around on the web to find a simple solution to the problem. There were many classes that already do this, but I found them way too complex.

So I decided to build my own!

Using the Code

Below are a few samples of how the classes can be used. The classes have many constructor and method overloads that allow reading/writing from/to files, strings and streams.

Using the CsvReader Class

List<List<string>> records = new List<List<string>>();

using (CsvReader reader = new CsvReader(FilePath, Encoding.Default))
{
    while (reader.ReadNextRecord())
        records.Add(reader.Fields);
} 

The CsvReader class has the following properties:

  • TrimColumns - Gets or sets whether column and heading values should be trimmed
  • HasHeaderRow - Gets or sets whether the CSV content has a header row
  • Fields - Gets the fields in the current Record
  • FieldCount - Gets the number of fields in the current record

Using the CsvFile Class

  CsvFile file = new CsvFile();
  file.Populate(FilePath, true);  

The CsvFile class has the following properties:

  • Headers - Gets the column headers
  • Records - Gets the records within the CSV file
  • HeaderCount - Gets the number of header columns
  • RecordsCount - Gets the number of records within the CSV file

Using the CsvWriter Class

  CsvFile csvFile = new CsvFile();
  csvFile.Populate(FilePath, true);

  using (CsvWriter writer = new CsvWriter())
  {
     writer.WriteCsv(csvFile, FilePath);
  }

The CsvWriter class has the following properties:

  • ReplaceCarriageReturnsAndLineFeedsFromFieldValues - Gets or sets whether carriage returns and line feeds should be replaced in field values.
  • CarriageReturnAndLineFeedReplacement - Gets or sets the character replacement for carriage returns and line feeds.

History

Version 1.0 (22-06-2010)

  • 1.0: First release

License

This article, along with any associated source code and files, is licensed under The MIT License

About the Author

CroweMan
Web Developer
United Kingdom United Kingdom
Member
I have been developing web and software applications for 9 years originally in Microsoft Visual Fox Pro. But for the last 8 years I have been using Microsoft.Net.
 
I love writing code and especially enjoy writing tools to aid development.
 
I have developed my own code generator which generates C# code from a SQL Server database. The generator generates Business Components, Data Components and entities and is optimised for performance as it uses stored procedures and SqlDataReaders.
 
FrameworkGen can be downloaded for free from http://www.elencysolutions.co.uk.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
SuggestionReadNextRecordmemberAlexander Kolenov22 Jun '12 - 1:30 
public bool ReadNextRecord()
{
    Fields = new List<string>();
    bool ColumnComlpete = false;
    bool inQuotes = false;
 
    _columnBuilder.Remove(0, _columnBuilder.Length);
 
    while(true)
    {
        string line = _streamReader.ReadLine();
        if(line == null)
        {
            if(inQuotes) throw new Exception("unexpected endof file in csv file");
            break;
        }
 
        // Iterate through every character in the line
        for (int i = 0; i < line.Length; i++)
        {
            char character = line[i];
 
            if (inQuotes)
            {
                if (character == '"')
                {
                    if (line.Length > i + 1)
                    {
                        if(line[i + 1] == '"')
                        {
                            _columnBuilder.Append(character);
                            i++;
                        }
                        else if(line[i + 1] == ',')
                        {
                            i++;
                            inQuotes = false;
                            ColumnComlpete = true;
                        }
                        else
                        {
                            throw new Exception("unexpected Quoter in csv file");
                        }
                    }
                    else
                    {
                        ColumnComlpete = true;
                    }
                }
                else
                {
                    _columnBuilder.Append(character);
                }
            }
            else
            {
                if (character == ',')
                {
                    ColumnComlpete = true;
                }
                else if (character == '"')
                {
                    inQuotes = true;
                }
                else
                {
                    _columnBuilder.Append(character);
                }
            }
 
            if (ColumnComlpete)
            {
                Fields.Add(TrimColumns ? _columnBuilder.ToString().Trim() : _columnBuilder.ToString());
                _columnBuilder.Remove(0, _columnBuilder.Length);
                ColumnComlpete = false;
            }
            if (line.Length <= i + 1 && line[i] == ',')
            {
                Fields.Add("");
            }
        }
        if(inQuotes)
        {
            _columnBuilder.Append(Environment.NewLine);
        }
        else
        {
            break;
        }
    }
 
    return Fields.Count != 0;
}

QuestionHow do I use CsvWrite to flush each row in a csv filememberMember 82787139 Dec '11 - 11:14 
I can't keep the big chunk in memory and so intend to write each row to the csv file as and when processed. The way I use it now, the first row is being overwritten. Is there a concept of index so I know which row number I am writing?
Bugbug with empty feildmembernoav6 Dec '11 - 0:39 
there is a bug with reading string
 
var file = new CsvFile(new CsvReader("hello,word,,1\r\nhello,,excel,2"));
    
new CsvWriter().Write(file, "D:\\01.csv");
 
empty field like "hello,,i,,am"
 

// If we are not currently inside a column
if (!inColumn)
{
    // If the current character is a double quote then the column value is contained within
    // double quotes, otherwise append the next character
    switch (character)
    {
        case ',':
            Fields.Add(string.Empty);
            break;
        case '"':
            inQuotes = true;
            break;
        default:
            _columnBuilder.Append(character);
            break;
    }
 
    inColumn = true;
    continue;
}

BugRe: bug with empty feildmemberizogi23 May '12 - 15:56 
Thanks for that. I ran into the same problem. The fix you've provided doesn't seem to work for cases where a line ends with a comma, however. Here's an additional change I made at the end of CvsReader.ParseLine(string line):
 
// If we are still inside a column add a new one, otherwise add an empty field because we ended on a comma
if (inColumn)
  Fields.Add(TrimColumns ? _columnBuilder.ToString().Trim() : _columnBuilder.ToString());
else
  Fields.Add(String.Empty);

GeneralRe: bug with empty feildmemberjemnet28 Jan '13 - 8:06 
This fix works if the line ends in a comma, but will blow up if the end character is a quote.
 
I moved the declaration of "character" outside the loop and modified this to be:
if (inColumn)
     Fields.Add(TrimColumns ? _columnBuilder.ToString().Trim() : _columnBuilder.ToString());
else if (character == ',')
     Fields.Add(String.Empty);

GeneralMy vote of 5memberMember 790749028 Aug '11 - 3:30 
it solve my problem.nice work!
Generalhere we go with a secound solutionmemberoscar@angress.de23 Feb '11 - 9:50 
i was also looking for a solution on this several days before
and that was my result.
 
http://oscar.angress.de/2011/02/17/csv-converter/
GeneralStyleCopped Version of this ProjectmemberTatworth21 Feb '11 - 10:23 
Would you be interested in a style-cop compliant version of your code?
GeneralMy vote of 5memberTatworth16 Feb '11 - 0:09 
Only suggestion to make is that the code be made Style Cop compliant
GeneralThanks!memberD-Three2 Nov '10 - 2:36 
I needed a simple csv writer and reader and this is just what I needed, thank you!
 
I only needed to do some small adjustments to get it work with VS2005 and .Net 2.0. And I also added a FieldValueSeparator property in the CsvReader and CsvWriter classes since Excel uses a semi colon as seperator (because of my regional settings).
 
Yes, maybe there are more extensive and faster readers/writers out there. But like you say, they are sometimes too complex. Your code does what is has to do and it is small and simple enough to figure out how it works. Good job!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 22 Jun 2010
Article Copyright 2010 by CroweMan
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid