362

I am trying to read a *.csv-file.

The *.csv-file consist of two columns separated by semicolon (";").

I am able to read the *.csv-file using StreamReader and able to separate each line by using the Split() function. I want to store each column into a separate array and then display it.

Is it possible to do that?

Matt
  • 21,449
  • 14
  • 100
  • 149
Rushabh Shah
  • 3,663
  • 3
  • 14
  • 4
  • 2
    @Marc: unfortunately in non-english cultures (e.g. Italian) when you save an excel to CSV it uses `";"` as separator... this has made CSV a non-standard imo :( – digEmAll Mar 12 '11 at 14:22
  • 28
    I always read CSV as character-separated-values since people call files CSV even if they don't use a comma as separator. And there are so many dialects with different quoting or escaping rules in practice that you can't really talk of a standard even if in theory there is a RFC. – CodesInChaos Mar 12 '11 at 14:31
  • 3
    CSV file extension name should now get change to DSV - *Delimiter Separated Values* File – Ambuj Sep 25 '19 at 11:07
  • 1
    For all of the answers that simply split the string on the delimiter character, this is not the best way to go. There are more rules to the CSV format that this will not cover. It is best to use a 3rd party parser. More info- https://dotnetcoretutorials.com/2018/08/04/csv-parsing-in-net-core/ – iliketocode Apr 21 '20 at 20:31

20 Answers20

484

You can do it like this:

using System.IO;

static void Main(string[] args)
{
    using(var reader = new StreamReader(@"C:\test.csv"))
    {
        List<string> listA = new List<string>();
        List<string> listB = new List<string>();
        while (!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            var values = line.Split(';');

            listA.Add(values[0]);
            listB.Add(values[1]);
        }
    }
}
iliketocode
  • 6,652
  • 4
  • 41
  • 57
Michael M.
  • 5,638
  • 1
  • 14
  • 17
  • 7
    Thanks for this, I had forgotten how to split lines in a csv file (dumb me!) but your solution helped me :) – Hallaghan Sep 15 '11 at 15:58
  • 1
    .EndOfStream is not available in .NET 1.1. Is while (reader.WriteLine) the way to go? – B. Clay Shannon May 28 '13 at 22:54
  • 1
    @ClayShannon The implementation of `EndOfStream` more or less checks to see if the current position of the reader is less than the length of the total number of bytes in the file. This works for me within my while constructor `rdr.BaseStream.Position < rdr.BaseStream.Length`. Remember a `StreamReader` is just a convenient wrapper around a `Stream` so with that being said you can implement your own custom methods if your version of .NET doesn't have them. – The Muffin Man Jun 29 '13 at 05:48
  • 6
    It's over 3 years later and this question is still helping someone. I feel bad that you didn't get an accept on this. – AdamMc331 Aug 12 '14 at 17:50
  • 14
    Does not handle field values with commas, etc. – Mike Aug 26 '14 at 18:39
  • 13
    Should use a `using` clause here, or at the very least manually `Close()` the `reader` as it's an `IDisposible` resource. – Assaf Israel May 29 '15 at 06:16
  • 37
    This also will not properly parse a CSV written like `column1;"Special ; char in string";column3` - https://tools.ietf.org/html/rfc4180 – Ole K Oct 23 '15 at 14:55
  • 2
    It's risky to handle all edge cases in csv parsing by writing your own. It'd be better to use a package made for this. I liked the one from [this answer](http://stackoverflow.com/a/16193999/375688) below. – TinyTimZamboni Dec 01 '16 at 19:10
  • I added a Console.WriteLine to loop through the list after the CSV is read into it. How would you go about telling the app that the CSV has headers? Just start at index 1 rather than 0? – B Minster Feb 09 '17 at 20:22
  • I got a system.IndexOutOfRangeException on column2.Add(splits[1]); – DanCode Jul 16 '19 at 20:05
  • Can anyone guide me on how to use this code for a 2D array of double[][] values instead of string? – Shayan Riyaz May 02 '20 at 01:29
215

My favourite CSV parser is one built into .NET library. This is a hidden treasure inside Microsoft.VisualBasic namespace. Below is a sample code:

using Microsoft.VisualBasic.FileIO;

var path = @"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
 csvParser.CommentTokens = new string[] { "#" };
 csvParser.SetDelimiters(new string[] { "," });
 csvParser.HasFieldsEnclosedInQuotes = true;

 // Skip the row with the column names
 csvParser.ReadLine();

 while (!csvParser.EndOfData)
 {
  // Read current line fields, pointer moves to the next line.
  string[] fields = csvParser.ReadFields();
  string Name = fields[0];
  string Address = fields[1];
 }
}

Remember to add reference to Microsoft.VisualBasic

More details about the parser is given here: http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html

iliketocode
  • 6,652
  • 4
  • 41
  • 57
Habeeb
  • 6,226
  • 1
  • 25
  • 29
  • 6
    I like this option the best. I don't have to worry about escape characters since the class is a CSV parser and not something being built manually. – Timothy Gonzalez Oct 10 '16 at 19:15
  • 25
    In case anyone runs into this and is wondering, you'll need to include the reference to `Microsoft.VisualBasic` framework assembly as it is not typically referenced by default. – apokryfos Feb 21 '17 at 15:45
  • 3
    I wish I had remembered this from my VB6 days, would have saved me a lot of time over the years. While some will rant about VB, I have no issue adding the dll & namespace to my code if it has value. This has A LOT of value. – Walter May 30 '18 at 15:56
  • 2
    This solution is a homerun. very reliable parser from my experience. – Glenn Ferrie Mar 28 '19 at 19:12
  • 3
    Why only in VB dll? – Mark Choi Dec 27 '19 at 07:53
  • 1
    This solution is way better than the other ones because it allows fields to have explicit values for comma's and new lines – WtFudgE Mar 05 '20 at 09:18
79

LINQ way:

var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
          select (from piece in line
                  select piece);

^^Wrong - Edit by Nick

It appears the original answerer was attempting to populate csv with a 2 dimensional array - an array containing arrays. Each item in the first array contains an array representing that line number with each item in the nested array containing the data for that specific column.

var csv = from line in lines
          select (line.Split(',')).ToArray();
Jonas
  • 73,844
  • 10
  • 134
  • 175
as-cii
  • 11,939
  • 4
  • 37
  • 43
  • 2
    Maybe I'm missing something, but I'm not sure what the point of your csv variable is - aren't you just re-creating the same data structure that is alread in lines? – Ben Hughes May 14 '13 at 01:10
  • @Ben: I think you need to learn about either Link Wray or the LINQ way. Unfortunately for me, this won't work in .NET 1.1 – B. Clay Shannon May 28 '13 at 22:35
  • @ClayShannon I'm farily fluent in LINQ, which is why I can't understand the point the statement, which (unless I'm missing something) results in exactly the same data structure as you started with. – Ben Hughes May 29 '13 at 23:25
  • 14
    @ClayShannon .NET 1.1 ? I'm...very sorry for you. – contactmatt Jun 03 '13 at 17:55
  • 5
    @contactmatt: I won't disabuse you of that sentiment. – B. Clay Shannon Jun 03 '13 at 19:01
  • 1
    @BenHughes You are right the LINQ is just duplicating the original data structure, and it's funny that it has so many upvotes - probably due to the fact that it looks concise, but a closer look reveals that this answer is not complete. – The Muffin Man Jun 29 '13 at 06:02
  • 9
    I also want to point out that csv's can be quoted... So using string.Split isn't a viable option. – Alxandr Jul 09 '13 at 10:48
  • 5
    I am getting: 'System.Array' does not contain a definition for 'Split' and no extension method 'Split' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?) – Kala J May 16 '14 at 19:22
  • 4
    You are getting System.Array doesnt contain a definition because lines is an IEnumerable(string []) so line is basically a string array that has one element. Just change that to var csv = from line in lines select (line[0].Split(',')).ToArray(); – Zein Sleiman Jun 13 '14 at 22:27
40

Just came across this library: https://github.com/JoshClose/CsvHelper

Very intuitive and easy to use. Has a nuget package too which made is quick to implement: http://nuget.org/packages/CsvHelper/1.17.0. Also appears to be actively maintained which I like.

Configuring it to use a semi-colon is easy: https://github.com/JoshClose/CsvHelper/wiki/Custom-Configurations

joshb
  • 4,904
  • 4
  • 39
  • 53
39

You can't create an array immediately because you need to know the number of rows from the beginning (and this would require to read the csv file twice)

You can store values in two List<T> and then use them or convert into an array using List<T>.ToArray()

Very simple example:

var column1 = new List<string>();
var column2 = new List<string>();
using (var rd = new StreamReader("filename.csv"))
{
    while (!rd.EndOfStream)
    {
        var splits = rd.ReadLine().Split(';');
        column1.Add(splits[0]);
        column2.Add(splits[1]);
    }
}
// print column1
Console.WriteLine("Column 1:");
foreach (var element in column1)
    Console.WriteLine(element);

// print column2
Console.WriteLine("Column 2:");
foreach (var element in column2)
    Console.WriteLine(element);

N.B.

Please note that this is just a very simple example. Using string.Split does not account for cases where some records contain the separator ; inside it.
For a safer approach, consider using some csv specific libraries like CsvHelper on nuget.

digEmAll
  • 53,114
  • 9
  • 109
  • 131
  • Does not account for `;` being a part of the value, example `"value with ; inside it"`. CSV surround values containing special characters with with double quotes to say it is a literal string. – ChickenFeet Dec 12 '18 at 08:19
  • 1
    @ChickenFeet: sure, that's the reason of the caption : *"Very simple example"*. Anyway I can add a note about that ;) – digEmAll Dec 12 '18 at 08:39
  • No worries, I noticed a lot of other answers here also do not account for it :) – ChickenFeet Dec 12 '18 at 09:00
  • 1
    Regex.Split(sr.ReadLine(), ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); //Found this on SO...quicker than a library. – Pinch Aug 07 '19 at 22:15
35

I usually use this parser from codeproject, since there's a bunch of character escapes and similar that it handles for me.

Paul
  • 32,974
  • 9
  • 79
  • 112
  • 2
    this thing is very good and fast. If you're in a business situation and need to get cracking use this. – gjvdkamp Mar 12 '11 at 14:45
  • 9
    This parser is available in the Nuget gallery as LumenWorks.Framework.IO, in case you don't want to register for CodeProject to download it. – Greg McCoy Sep 03 '15 at 19:14
30

Here is my variation of the top voted answer:

var contents = File.ReadAllText(filename).Split('\n');
var csv = from line in contents
          select line.Split(',').ToArray();

The csv variable can then be used as in the following example:

int headerRows = 5;
foreach (var row in csv.Skip(headerRows)
    .TakeWhile(r => r.Length > 1 && r.Last().Trim().Length > 0))
{
    String zerothColumnValue = row[0]; // leftmost column
    var firstColumnValue = row[1];
}
tomsv
  • 6,807
  • 5
  • 51
  • 85
11

If you need to skip (head-)lines and/or columns, you can use this to create a 2-dimensional array:

    var lines = File.ReadAllLines(path).Select(a => a.Split(';'));
    var csv = (from line in lines               
               select (from col in line
               select col).Skip(1).ToArray() // skip the first column
              ).Skip(2).ToArray(); // skip 2 headlines

This is quite useful if you need to shape the data before you process it further (assuming the first 2 lines consist of the headline, and the first column is a row title - which you don't need to have in the array because you just want to regard the data).

N.B. You can easily get the headlines and the 1st column by using the following code:

    var coltitle = (from line in lines 
                    select line.Skip(1).ToArray() // skip 1st column
                   ).Skip(1).Take(1).FirstOrDefault().ToArray(); // take the 2nd row
    var rowtitle = (from line in lines select line[0] // take 1st column
                   ).Skip(2).ToArray(); // skip 2 headlines

This code example assumes the following structure of your *.csv file:

CSV Matrix

Note: If you need to skip empty rows - which can by handy sometimes, you can do so by inserting

    where line.Any(a=>!string.IsNullOrWhiteSpace(a))

between the from and the select statement in the LINQ code examples above.

Matt
  • 21,449
  • 14
  • 100
  • 149
10

You can use Microsoft.VisualBasic.FileIO.TextFieldParser dll in C# for better performance

get below code example from above article

static void Main()
{
    string csv_file_path=@"C:\Users\Administrator\Desktop\test.csv";

    DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);

    Console.WriteLine("Rows count:" + csvData.Rows.Count);

    Console.ReadLine();
}


private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
    DataTable csvData = new DataTable();

    try
    {

    using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
        {
            csvReader.SetDelimiters(new string[] { "," });
            csvReader.HasFieldsEnclosedInQuotes = true;
            string[] colFields = csvReader.ReadFields();
            foreach (string column in colFields)
            {
                DataColumn datecolumn = new DataColumn(column);
                datecolumn.AllowDBNull = true;
                csvData.Columns.Add(datecolumn);
            }

            while (!csvReader.EndOfData)
            {
                string[] fieldData = csvReader.ReadFields();
                //Making empty value as null
                for (int i = 0; i < fieldData.Length; i++)
                {
                    if (fieldData[i] == "")
                    {
                        fieldData[i] = null;
                    }
                }
                csvData.Rows.Add(fieldData);
            }
        }
    }
    catch (Exception ex)
    {
    }
    return csvData;
}
Tshilidzi Mudau
  • 5,472
  • 6
  • 32
  • 44
kombsh
  • 5,078
  • 3
  • 38
  • 42
  • 9
    It's not as efficient because Split doesn't do everything that TextFieldParser does. For example, skip comment lines, handle quoted fields, and remove beginning/trailing whitespace. Not exactly a 1:1 comparison. – Robert McKee Feb 17 '15 at 17:37
5

Hi all, I created a static class for doing this. + column check + quota sign removal

public static class CSV
{
    public static List<string[]> Import(string file, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
    {
        return ReadCSVFile(file, csvDelimiter, ignoreHeadline, removeQuoteSign);
    }

    private static List<string[]> ReadCSVFile(string filename, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
    {
        string[] result = new string[0];
        List<string[]> lst = new List<string[]>();

        string line;
        int currentLineNumner = 0;
        int columnCount = 0;

        // Read the file and display it line by line.  
        using (System.IO.StreamReader file = new System.IO.StreamReader(filename))
        {
            while ((line = file.ReadLine()) != null)
            {
                currentLineNumner++;
                string[] strAr = line.Split(csvDelimiter);
                // save column count of dirst line
                if (currentLineNumner == 1)
                {
                    columnCount = strAr.Count();
                }
                else
                {
                    //Check column count of every other lines
                    if (strAr.Count() != columnCount)
                    {
                        throw new Exception(string.Format("CSV Import Exception: Wrong column count in line {0}", currentLineNumner));
                    }
                }

                if (removeQuoteSign) strAr = RemoveQouteSign(strAr);

                if (ignoreHeadline)
                {
                    if(currentLineNumner !=1) lst.Add(strAr);
                }
                else
                {
                    lst.Add(strAr);
                }
            }

        }

        return lst;
    }
    private static string[] RemoveQouteSign(string[] ar)
    {
        for (int i = 0;i< ar.Count() ; i++)
        {
            if (ar[i].StartsWith("\"") || ar[i].StartsWith("'")) ar[i] = ar[i].Substring(1);
            if (ar[i].EndsWith("\"") || ar[i].EndsWith("'")) ar[i] = ar[i].Substring(0,ar[i].Length-1);

        }
        return ar;
    }

}
4
var firstColumn = new List<string>();
var lastColumn = new List<string>();

// your code for reading CSV file

foreach(var line in file)
{
    var array = line.Split(';');
    firstColumn.Add(array[0]);
    lastColumn.Add(array[1]);
}

var firstArray = firstColumn.ToArray();
var lastArray = lastColumn.ToArray();
Jakub Konecki
  • 44,070
  • 6
  • 84
  • 125
  • Thanks for your help. It might help to solve my problem. Actually I have to read data from file and then insert into database. At time of inserting I am getting primary key constraint error(as I already have data in database). So, I need to program such that with variable already exist then update the data. – Rushabh Shah Mar 12 '11 at 14:25
  • I assume the first value if PK - you need to get a record by id from database and if it exists than issue an UPDATE statement, otherwise insert a new record. – Jakub Konecki Mar 12 '11 at 16:15
4

I have spend few hours searching for a right library, but finally I wrote my own code :) You can read file (or database) with whatever tools you want and then apply the following routine to each line:

private static string[] SmartSplit(string line, char separator = ',')
{
    var inQuotes = false;
    var token = "";
    var lines = new List<string>();
    for (var i = 0; i < line.Length; i++) {
        var ch = line[i];
        if (inQuotes) // process string in quotes, 
        {
            if (ch == '"') {
                if (i<line.Length-1 && line[i + 1] == '"') {
                    i++;
                    token += '"';
                }
                else inQuotes = false;
            } else token += ch;
        } else {
            if (ch == '"') inQuotes = true;
            else if (ch == separator) {
                lines.Add(token);
                token = "";
                } else token += ch;
            }
    }
    lines.Add(token);
    return lines.ToArray();
}
Zbyszek Swirski
  • 159
  • 1
  • 11
3

Here's a special case where one of data field has semicolon (";") as part of it's data in that case most of answers above will fail.

Solution it that case will be

string[] csvRows = System.IO.File.ReadAllLines(FullyQaulifiedFileName);
string[] fields = null;
List<string> lstFields;
string field;
bool quoteStarted = false;
foreach (string csvRow in csvRows)
{
    lstFields = new List<string>();
    field = "";
    for (int i = 0; i < csvRow.Length; i++)
    {
        string tmp = csvRow.ElementAt(i).ToString();
        if(String.Compare(tmp,"\"")==0)
        {
            quoteStarted = !quoteStarted;
        }
        if (String.Compare(tmp, ";") == 0 && !quoteStarted)
        {
            lstFields.Add(field);
            field = "";
        }
        else if (String.Compare(tmp, "\"") != 0)
        {
            field += tmp;
        }
    }
    if(!string.IsNullOrEmpty(field))
    {
        lstFields.Add(field);
        field = "";
    }
// This will hold values for each column for current row under processing
    fields = lstFields.ToArray(); 
}
Peet
  • 371
  • 4
  • 5
Yogesh
  • 1,465
  • 17
  • 36
2

The open-source Angara.Table library allows to load CSV into typed columns, so you can get the arrays from the columns. Each column can be indexed both by name or index. See http://predictionmachines.github.io/Angara.Table/saveload.html.

The library follows RFC4180 for CSV; it enables type inference and multiline strings.

Example:

using System.Collections.Immutable;
using Angara.Data;
using Angara.Data.DelimitedFile;

...

ReadSettings settings = new ReadSettings(Delimiter.Semicolon, false, true, null, null);
Table table = Table.Load("data.csv", settings);
ImmutableArray<double> a = table["double-column-name"].Rows.AsReal;

for(int i = 0; i < a.Length; i++)
{
    Console.WriteLine("{0}: {1}", i, a[i]);
}

You can see a column type using the type Column, e.g.

Column c = table["double-column-name"];
Console.WriteLine("Column {0} is double: {1}", c.Name, c.Rows.IsRealColumn);

Since the library is focused on F#, you might need to add a reference to the FSharp.Core 4.4 assembly; click 'Add Reference' on the project and choose FSharp.Core 4.4 under "Assemblies" -> "Extensions".

1

I have been using csvreader.com(paid component) for years, and I have never had a problem. It is solid, small and fast, but you do have to pay for it. You can set the delimiter to whatever you like.

using (CsvReader reader = new CsvReader(s) {
    reader.Settings.Delimiter = ';';
    reader.ReadHeaders();  // if headers on a line by themselves.  Makes reader.Headers[] available
    while (reader.ReadRecord())
        ... use reader.Values[col_i] ...
}
abmv
  • 6,716
  • 16
  • 59
  • 99
Oliver Bock
  • 4,185
  • 3
  • 33
  • 56
1

I am just student working on my master's thesis, but this is the way I solved it and it worked well for me. First you select your file from directory (only in csv format) and then you put the data into the lists.

List<float> t = new List<float>();
List<float> SensorI = new List<float>();
List<float> SensorII = new List<float>();
List<float> SensorIII = new List<float>();
using (OpenFileDialog dialog = new OpenFileDialog())
{
    try
    {
        dialog.Filter = "csv files (*.csv)|*.csv";
        dialog.Multiselect = false;
        dialog.InitialDirectory = ".";
        dialog.Title = "Select file (only in csv format)";
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            var fs = File.ReadAllLines(dialog.FileName).Select(a => a.Split(';'));
            int counter = 0;
            foreach (var line in fs)
            {
                counter++;
                if (counter > 2)    // Skip first two headder lines
                {
                    this.t.Add(float.Parse(line[0]));
                    this.SensorI.Add(float.Parse(line[1]));
                    this.SensorII.Add(float.Parse(line[2]));
                    this.SensorIII.Add(float.Parse(line[3]));
                }
            }
        }
    }
    catch (Exception exc)
    {
        MessageBox.Show(
            "Error while opening the file.\n" + exc.Message, 
            this.Text, 
            MessageBoxButtons.OK, 
            MessageBoxIcon.Error
        );
    }
}
php-dev
  • 6,340
  • 4
  • 18
  • 37
Daniel
  • 11
  • 1
1

My simple static methods to convert csv line to array, and array to csv line.

public static string CsvRowFromStringArray(string[] csvData, char fieldSeparator = ',', char stringQuote = '"')
{
    csvData = csvData.Select(element => {
        if (element.Contains(stringQuote))
        {
            element = element.Replace(stringQuote.ToString(), stringQuote.ToString() + stringQuote.ToString());
        }
        if (element.Contains(fieldSeparator))
        {
            element = "\"" + element + "\"";
        }
        return element;
    }).ToArray();
    return string.Join(fieldSeparator.ToString(), csvData);
}

public static string[] CsvRowToStringArray(string csvRow, char fieldSeparator = ',', char stringQuote = '"')
{
    char tempQuote = (char)162;
    while (csvRow.Contains(tempQuote)) { tempQuote = (char)(tempQuote + 1); }
    char tempSeparator = (char)(tempQuote + 1);
    while (csvRow.Contains(tempSeparator)) { tempSeparator = (char)(tempSeparator + 1); }

    csvRow = csvRow.Replace(stringQuote.ToString() + stringQuote.ToString(), tempQuote.ToString());
    var csvArray = csvRow.Split(fieldSeparator).ToList().Aggregate("",
        (string row, string item) =>
        {
            if (row.Count((ch) => ch == stringQuote) % 2 == 0) { return row + (row.Length > 0 ? tempSeparator.ToString() : "") + item; }
            else { return row + fieldSeparator + item; }
        },
        (string row) => row.Split(tempSeparator).Select((string item) => item.Trim(stringQuote).Replace(tempQuote, stringQuote))).ToArray();
    return csvArray;
}

private bool CsvTestError()
{
    string correctString = "0;a;\"b; c\";\"\"xy;\"this;is; one \"\"long; cell\"\"\"";
    string[] correctArray = new string[] { "0", "a", "b; c", "\"xy", "this;is; one \"long; cell\"" };

    bool error = string.Join("°", CsvRowToStringArray(correctString, ';')) != string.Join("°", correctArray);
    error = (CsvRowFromStringArray(correctArray, ';') != correctString) || error;
    return error;
}
Atiris
  • 2,289
  • 24
  • 39
0

Still wrong. You need to compensate for "" in quotes. Here is my solution Microsoft style csv.

               /// <summary>
    /// Microsoft style csv file.  " is the quote character, "" is an escaped quote.
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="sepChar"></param>
    /// <param name="quoteChar"></param>
    /// <param name="escChar"></param>
    /// <returns></returns>
    public static List<string[]> ReadCSVFileMSStyle(string fileName, char sepChar = ',', char quoteChar = '"')
    {
        List<string[]> ret = new List<string[]>();

        string[] csvRows = System.IO.File.ReadAllLines(fileName);

        foreach (string csvRow in csvRows)
        {
            bool inQuotes = false;
            List<string> fields = new List<string>();
            string field = "";
            for (int i = 0; i < csvRow.Length; i++)
            {
                if (inQuotes)
                {
                    // Is it a "" inside quoted area? (escaped litteral quote)
                    if(i < csvRow.Length - 1 && csvRow[i] == quoteChar && csvRow[i+1] == quoteChar)
                    {
                        i++;
                        field += quoteChar;
                    }
                    else if(csvRow[i] == quoteChar)
                    {
                        inQuotes = false;
                    }
                    else
                    {
                        field += csvRow[i];
                    }
                }
                else // Not in quoted region
                {
                     if (csvRow[i] == quoteChar)
                    {
                        inQuotes = true;
                    }
                    if (csvRow[i] == sepChar)
                    {
                        fields.Add(field);
                        field = "";
                    }
                    else 
                    {
                        field += csvRow[i];
                    }
                }
            }
            if (!string.IsNullOrEmpty(field))
            {
                fields.Add(field);
                field = "";
            }
            ret.Add(fields.ToArray());
        }

        return ret;
    }
}
R Keene
  • 63
  • 2
0

I have a library that is doing exactly you need.

Some time ago I had wrote simple and fast enough library for work with CSV files. You can find it by the following link: https://github.com/ukushu/DataExporter

It works with CSV like with 2 dimensions array. Exactly like you need.

As example, in case of you need all of values of 3rd row only you need is to write:

Csv csv = new Csv();

csv.FileOpen("c:\\file1.csv");

var allValuesOf3rdRow = csv.Rows[2];

or to read 2nd cell of

var value = csv.Rows[2][1];
callisto
  • 4,641
  • 9
  • 48
  • 86
Andrew
  • 5,048
  • 4
  • 35
  • 58
-1

look at this

using CsvFramework;

using System.Collections.Generic;

namespace CvsParser {

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Order> Orders { get; set; }        
}

public class Order
{
    public int Id { get; set; }

    public int CustomerId { get; set; }
    public int Quantity { get; set; }

    public int Amount { get; set; }

    public List<OrderItem> OrderItems { get; set; }

}

public class Address
{
    public int Id { get; set; }
    public int CustomerId { get; set; }

    public string Name { get; set; }
}

public class OrderItem
{
    public int Id { get; set; }
    public int OrderId { get; set; }

    public string ProductName { get; set; }
}

class Program
{
    static void Main(string[] args)
    {

        var customerLines = System.IO.File.ReadAllLines(@"Customers.csv");
        var orderLines = System.IO.File.ReadAllLines(@"Orders.csv");
        var orderItemLines = System.IO.File.ReadAllLines(@"OrderItemLines.csv");

        CsvFactory.Register<Customer>(builder =>
        {
            builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
            builder.Add(a => a.Name).Type(typeof(string)).Index(1);
            builder.AddNavigation(n => n.Orders).RelationKey<Order, int>(k => k.CustomerId);

        }, false, ',', customerLines);

        CsvFactory.Register<Order>(builder =>
        {
            builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
            builder.Add(a => a.CustomerId).Type(typeof(int)).Index(1);
            builder.Add(a => a.Quantity).Type(typeof(int)).Index(2);
            builder.Add(a => a.Amount).Type(typeof(int)).Index(3);
            builder.AddNavigation(n => n.OrderItems).RelationKey<OrderItem, int>(k => k.OrderId);

        }, true, ',', orderLines);


        CsvFactory.Register<OrderItem>(builder =>
        {
            builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
            builder.Add(a => a.OrderId).Type(typeof(int)).Index(1);
            builder.Add(a => a.ProductName).Type(typeof(string)).Index(2);


        }, false, ',', orderItemLines);



        var customers = CsvFactory.Parse<Customer>();


    }
}

}

tobias
  • 1,274
  • 3
  • 19
  • 44