Reputation: 3428
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
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
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
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
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
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
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
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