Ayb4btu
Ayb4btu

Reputation: 3428

Read all values from CSV into a List using CsvHelper

So I've been reading that I shouldn't write my own CSV reader/writer, so I've been trying to use the CsvHelper library installed via nuget. The CSV file is a grey scale image, with the number of rows being the image height and the number columns the width. I would like to read the values row-wise into a single List<string> or List<byte>.

The code I have so far is:

using CsvHelper;

public static List<string> ReadInCSV(string absolutePath)
{
    IEnumerable<string> allValues;

    using (TextReader fileReader = File.OpenText(absolutePath))
    {
        var csv = new CsvReader(fileReader);
        csv.Configuration.HasHeaderRecord = false;
        allValues = csv.GetRecords<string>
    }

    return allValues.ToList<string>();
}

But allValues.ToList<string>() is throwing a:

CsvConfigurationException was unhandled by user code

An exception of type 'CsvHelper.Configuration.CsvConfigurationException' occurred in CsvHelper.dll but was not handled in user code

Additional information: Types that inherit IEnumerable cannot be auto mapped. Did you accidentally call GetRecord or WriteRecord which acts on a single record instead of calling GetRecords or WriteRecords which acts on a list of records?

GetRecords is probably expecting my own custom class, but I'm just wanting the values as some primitive type or string. Also, I suspect the entire row is being converted to a single string, instead of each value being a separate string.

Upvotes: 33

Views: 131605

Answers (7)

lead
lead

Reputation: 131

The whole point here is to read all lines of CSV and deserialize it to a collection of objects. I'm not sure why do you want to read it as a collection of strings. Generic ReadAll() would probably work the best for you in that case as stated before. This library shines when you use it for that purpose:

    using CsvHelper;
    using System.Linq;
    using System.Globalization;
                    
    …

    var switzerland = new CultureInfo (name: "de-CH", useUserOverride: false);

    using (var reader = new StreamReader(path))
    using (var csv = new CsvReader(reader, switzerland))
    {
        var yourList = csv.GetRecords<YourClass>().ToList();
    }

If you don't use ToList() - it will return a single record at a time (for better performance), please read https://joshclose.github.io/CsvHelper/examples/reading/enumerate-class-records

Upvotes: 8

HO LI Pin
HO LI Pin

Reputation: 1691

Below .NET code can turn all cells values inside a CVS file into List<string> object . Tested it to read a CSV file with 11 columns X 31 rows , all cell data were read successfully.

First , install CsvHelper 30.0.1 , then use the library on your code

using CsvHelper;
using CsvHelper.Configuration;

Then , use these code to save cells value into .NET list string object

    // Replace with your CSV file path
    string filePath = @"C:\Temp\MyRawData.csv";

    // Configure CSV Reader
    CsvConfiguration config = new CsvConfiguration(CultureInfo.InvariantCulture)
    { HasHeaderRecord = false };
    StreamReader reader = new StreamReader(filePath);

    // Declare List<string> Object to hold data later
    List<string> cellDataList = new List<string>();

    // Fetch all cells value
    using (var csv = new CsvReader(reader, config))
    {

        while (csv.Read())
        {
            int MaxIndex = csv.Parser.Count;
            for (var i = 0; i < MaxIndex; i++)
            {
                // Then Save into List<string> Object
                cellDataList.Add(csv.GetField<string>(i));
            }
        }
    }

Upvotes: 2

Josh Close
Josh Close

Reputation: 23413

If all you need is the string values for each row in an array, you could use the parser directly.

var parser = new CsvParser( textReader );
while( true )
{
    string[] row = parser.Read();
    if( row == null )
    {
        break;
    }
}

http://joshclose.github.io/CsvHelper/#reading-parsing

Update

Version 3 has support for reading and writing IEnumerable properties.

Upvotes: 20

mognito
mognito

Reputation: 1

static void WriteCsvFile(string filename, IEnumerable<Person> people)
    {

        StreamWriter textWriter = File.CreateText(filename);

        var csvWriter = new CsvWriter(textWriter, System.Globalization.CultureInfo.CurrentCulture);

        csvWriter.WriteRecords(people);

        textWriter.Close();

    }

Upvotes: -4

sal
sal

Reputation: 39

Please try this. This had worked for me.

TextReader reader = File.OpenText(filePath);
            CsvReader csvFile = new CsvReader(reader);
            csvFile.Configuration.HasHeaderRecord = true;
            csvFile.Read();
            var records = csvFile.GetRecords<Server>().ToList();

Server is an entity class. This is how I created.

 public class Server
    {
        private string details_Table0_ProductName;
        public string Details_Table0_ProductName
        {
            get
            {
                return details_Table0_ProductName;
            }
            set
            {
                this.details_Table0_ProductName = value;
            }
        }

        private string details_Table0_Version;
        public string Details_Table0_Version
        {
            get
            {
                return details_Table0_Version;
            }
            set
            {
                this.details_Table0_Version = value;
            }
        }       
    }

Upvotes: 2

Marc L.
Marc L.

Reputation: 3399

You are close. It isn't that it's trying to convert the row to a string. CsvHelper tries to map each field in the row to the properties on the type you give it, using names given in a header row. Further, it doesn't understand how to do this with IEnumerable types (which string implements) so it just throws when it's auto-mapping gets to that point in testing the type.


That is a whole lot of complication for what you're doing. If your file format is sufficiently simple, which yours appear to be--well known field format, neither escaped nor quoted delimiters--I see no reason why you need to take on the overhead of importing a library. You should be able to enumerate the values as needed with System.IO.File.ReadLines() and String.Split().

//pseudo-code...you don't need CsvHelper for this
IEnumerable<string> GetFields(string filepath)
{
  foreach(string row in File.ReadLines(filepath))
  {
    foreach(string field in row.Split(',')) yield return field;
  }
}

Upvotes: 2

masinger
masinger

Reputation: 775

According to @Marc L's post you can try this:

public static List<string> ReadInCSV(string absolutePath) {
    List<string> result = new List<string>();
    string value;
    using (TextReader fileReader = File.OpenText(absolutePath)) {
        var csv = new CsvReader(fileReader);
        csv.Configuration.HasHeaderRecord = false;
        while (csv.Read()) {
           for(int i=0; csv.TryGetField<string>(i, out value); i++) {
                result.Add(value);
            }
        }
    }
    return result;
}

Upvotes: 30

Related Questions