38

I'd like to create an array from a CSV file.

This is about as simple as you can imagine, the CSV file will only ever have one line and these values:

Device, SignalStrength, Location, Time, Age.

I'd like to put these values into one dimensional array.

I've tried some examples but they've all been more complicated than required.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
DNN
  • 861
  • 2
  • 11
  • 17

7 Answers7

65

You can try the some thing like the below LINQ snippet.

string[] allLines = File.ReadAllLines(@"E:\Temp\data.csv");

    var query = from line in allLines
                let data = line.Split(',')
                select new
                {
                    Device = data[0],
                    SignalStrength = data[1],
                    Location = data[2], 
                    Time = data[3],
                    Age = Convert.ToInt16(data[4])
                };

UPDATE: Over a period of time, things evolved. As of now, I would prefer to use this library http://www.aspnetperformance.com/post/LINQ-to-CSV-library.aspx

Ramesh
  • 13,043
  • 3
  • 52
  • 88
  • 7
    Hi Ramesh.. your solution is great.. but how do you escape the commas?? – andrew0007 Apr 11 '11 at 14:58
  • @andrew007 - First thing which came to my mind is to use regex to split. check out http://regexadvice.com/blogs/wayneking/archive/2004/01/12/271.aspx – Ramesh Apr 14 '11 at 15:22
  • 14
    @ramesh "Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems." - Jamie Zawinski. Have a look at http://secretgeek.net/csv_trouble.asp. – David Keaveny Dec 09 '11 at 04:00
  • LINQ-to-CSV is definitely the way to go. So simple to use! – Jonathon Reinhart Nov 07 '13 at 07:14
52

If there is only ever one line then do something like this:

using System;
using System.IO;

class Program
{
    static void Main()
    {
        String[] values = File.ReadAllText(@"d:\test.csv").Split(',');
    }
}
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • 73
    No, no, no this is way too complex!! – ChaosPandion Jan 28 '10 at 06:21
  • 106
    If a any of the fields contain a comma, this will fail. – Petrus Theron Jun 22 '12 at 00:12
  • 5
    How do you deal with new lines? – nonsensickle Jan 13 '14 at 02:52
  • 1
    @pate if any of the fields contain a comma than this is not a valid csv, which becomes a data issue. – jamesdeath123 Jan 24 '14 at 19:38
  • 17
    @jamesdeath123 CSV column values can contain commas, so long as they are wrapped in double quotes, e.g. "this is, a test". – Petrus Theron Jan 25 '14 at 09:37
  • Even though my string is wrapped in double quotes, I still get it chopped. – Kala J May 20 '14 at 19:49
  • 3
    I don't think this will be a correct answer since there are some cases where you might be having comma as data. e.g. an employee record as CSV row "Mr.","Scott","","babble","","scotty@hotmail.com","Ralph Diagnostics","","Manager, CRM and Data Analytics","analysis" when we parse this data, the manager, CRM and Data Analytics will become two columns where as it is just a single column data – Albert Arul prakash Jul 02 '14 at 18:53
  • 13
    This answer is wrong and should not be the accepted answer since it will not handle anything but the most basic csv files, and most systems that can create CSV will be able to create files that this solution would fail to load. Among them the type of files I am looking for a solution for. – David Mårtensson Mar 11 '15 at 15:18
  • 3
    I agree with David. This should not be marked as a correct answer. Try this: https://gist.github.com/mariodivece/9614872 – Mario Jun 14 '15 at 18:41
  • Also agree this should not be the accepted answer and it's rating is way too high !!! – AFract Oct 13 '15 at 08:17
  • To deal with commas in quotes you can use Regex.Split() and use a Regex pattern like (?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*) taken from [Split comma with quoted commas](http://stackoverflow.com/questions/3776458/split-a-comma-separated-string-with-both-quoted-and-unquoted-strings) – SymbioticKaos Apr 14 '16 at 12:22
8

Here's a simple function I made. It accepts a string CSV line and returns an array of fields:

It works well with Excel generated CSV files, and many other variations.

    public static string[] ParseCsvRow(string r)
    {

        string[] c;
        string t;
        List<string> resp = new List<string>();
        bool cont = false;
        string cs = "";

        c = r.Split(new char[] { ',' }, StringSplitOptions.None);

        foreach (string y in c)
        {
            string x = y;


            if (cont)
            {
                // End of field
                if (x.EndsWith("\""))
                {
                    cs += "," + x.Substring(0, x.Length - 1);
                    resp.Add(cs);
                    cs = "";
                    cont = false;
                    continue;

                }
                else
                {
                    // Field still not ended
                    cs += "," + x;
                    continue;
                }
            }

            // Fully encapsulated with no comma within
            if (x.StartsWith("\"") && x.EndsWith("\""))
            {
                if ((x.EndsWith("\"\"") && !x.EndsWith("\"\"\"")) && x != "\"\"")
                {
                    cont = true;
                    cs = x;
                    continue;
                }

                resp.Add(x.Substring(1, x.Length - 2));
                continue;
            }

            // Start of encapsulation but comma has split it into at least next field
            if (x.StartsWith("\"") && !x.EndsWith("\""))
            {
                cont = true;
                cs += x.Substring(1);
                continue;
            }

            // Non encapsulated complete field
            resp.Add(x);

        }

        return resp.ToArray();

    }
Chris Wilson
  • 113
  • 1
  • 3
4

This fixed version of code above remember the last element of CVS row ;-)

(tested with a CSV file with 5400 rows and 26 elements by row)

   public static string[] CSVRowToStringArray(string r, char fieldSep = ',', char stringSep = '\"')  {
            bool bolQuote = false;
            StringBuilder bld = new StringBuilder();
            List<string> retAry = new List<string>();

            foreach (char c in r.ToCharArray())
                if ((c == fieldSep && !bolQuote))
                {
                    retAry.Add(bld.ToString());
                    bld.Clear();
                }
                else
                    if (c == stringSep)
                        bolQuote = !bolQuote;
                    else
                        bld.Append(c);

            /* to solve the last element problem */
            retAry.Add(bld.ToString()); /* added this line */
            return retAry.ToArray();
        }
Paolo D.a
  • 41
  • 1
3

This is what I used in a project, parses a single line of data.

    private string[] csvParser(string csv, char separator = ',')
    {
        List <string> = new <string>();
        string[] temp = csv.Split(separator);
        int counter = 0;
        string data = string.Empty;
        while (counter < temp.Length)
        {
            data = temp[counter].Trim();
            if (data.Trim().StartsWith("\""))
            {
                bool isLast = false;
                while (!isLast && counter < temp.Length)
                {
                    data += separator.ToString() + temp[counter + 1];
                    counter++;
                    isLast = (temp[counter].Trim().EndsWith("\""));
                }
            }
            parsed.Add(data);
            counter++;
        }

        return parsed.ToArray();

    }

http://zamirsblog.blogspot.com/2013/09/c-csv-parser-csvparser.html

Zamir
  • 79
  • 4
  • I think line 3 should read: List parsed = new List(); – Matiaan Apr 20 '15 at 11:16
  • Nice try but unfortunately fails with an "out of array boundary" exception on line data += separator.ToString() + temp[counter + 1]; on a well formed line :( – AFract Oct 13 '15 at 08:45
2

My solution handles quotes, overriding field and string separators, etc. It is short and sweet.

    public static string[] CSVRowToStringArray(string r, char fieldSep = ',', char stringSep = '\"')
    {
        bool bolQuote = false;
        StringBuilder bld = new StringBuilder();
        List<string> retAry = new List<string>();

        foreach (char c in r.ToCharArray())
            if ((c == fieldSep && !bolQuote))
            {
                retAry.Add(bld.ToString());
                bld.Clear();
            }
            else
                if (c == stringSep)
                    bolQuote = !bolQuote;
                else
                    bld.Append(c);

        return retAry.ToArray();
    }
  • This solution seems to lose the last value on the line, even on very simple test with no quote – AFract Oct 13 '15 at 08:44
0

First of all need to understand what is CSV and how to write it.

(Most of answers (all of them at the moment) do not use this requirements, that's why they all is wrong!)

  1. Every next string ( /r/n ) is next "table" row.
  2. "Table" cells is separated by some delimiter symbol.
  3. As delimiter can be used ANY symbol. Often this is \t or ,.
  4. Each cell possibly can contain this delimiter symbol inside of the cell (cell must to start with double quotes symbol and to have double quote in the end in this case)
  5. Each cell possibly can contains /r/n symbols inside of the cell (cell must to start with double quotes symbol and to have double quote in the end in this case)

Some time ago I had wrote simple class for CSV read/write based on standard Microsoft.VisualBasic.FileIO library. Using this simple class you will be able to work with CSV like with 2 dimensions array.

Simple example of using my library:

Csv csv = new Csv("\t");//delimiter symbol

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

var row1Cell6Value = csv.Rows[0][5];

csv.AddRow("asdf","asdffffff","5")

csv.FileSave("c:\\file2.csv");

You can find my class by the following link and investigate how it's written: https://github.com/ukushu/DataExporter

This library code is really fast in work and source code is really short.

PS: In the same time this solution will not work for unity.

PS2: Another solution is to work with library "LINQ-to-CSV". It must also work well. But it's will be bigger.

Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101