Csvhelper: Getting Count

Created on 12 Mar 2018  路  5Comments  路  Source: JoshClose/CsvHelper

I have similar issue on #92. But I'm not sure whether I should've bumped the issue that has been over 5 years old, so I'm creating a new one.

I'm aware that calling Count() on the enumerated records will cause the cursor goes to the end and further operation/foreach loop on the records will return nothing.

The outline of my code is like this

````C#
var myCSV = new CsvReader(File.OpenText(txtBox_CSVFile.Text));
myCSV.Configuration.RegisterClassMap();

var record = new MyRecordClass();
var allRecords = myCSV.EnumerateRecords(record);
int recordsLength = allRecords.Count<MyRecordClass>();

foreach (var r in allRecords)
{
    /* some read/write operation here
    */
    scannedCSVEntry++;
    progress.value = scannedCSVEntry/recordsLength;
}

````

The recordsLength is important here as I need to update the progress bar while I'm processing the entry

But how do I get around this?

Most helpful comment

If you want just update progress bar, then using stream.Position worked for me with large files without reading the entire file first:

using(StreamReader sr = File.OpenText(txtBox_CSVFile.Text))
{
   var csvReader = new new CsvHelper.CsvReader(sr);
    while (csvReader.Read())
    {
         double progress = (double)sr.BaseStream.Position / sr.BaseStream.Length;
    }
}

it should work also with GetRecords, but I've not tested:

foreach(var record in csvReader.GetRecords<MyRecordClass>())
{
    double progress = (double)sr.BaseStream.Position / sr.BaseStream.Length;
}

All 5 comments

There are a few ways.

  1. Pull the whole thing into memory by doing a ToList. You can then do several operations over the data, including Count.
  2. Parser the whole file. You can use just the parser to go through the whole file and count the records. This should be pretty fast because it's not creating any class objects or doing any type conversions.
  3. Just count the line endings in the file. You can then use the Context.RawRow property to do your progress.

Thanks,
I finally picked method 2.

C# StreamReader sr = File.OpenText(txtBox_CSVFile.Text); int recordsLength = 0; while(sr.ReadLine() != null) { ++recordsLength; } recordsLength--; // discount 1 line because there are column headers in first row. Console.WriteLine("recordsLength : " + recordsLength); sr.Close();

Does EnumerateRecords() automatically close the stream after hydrating all the entries? I'm wondering whether I should call Close() after calling the function.

My suggestion is to wrap in a using block.

using(StreamReader sr = File.OpenText(txtBox_CSVFile.Text))
{
    int recordsLength = 0;
    while(sr.ReadLine() != null)
    {
        ++recordsLength;
    }
    recordsLength--; // discount 1 line because there are column headers in first row.
    Console.WriteLine("recordsLength : " + recordsLength);
}

If you want just update progress bar, then using stream.Position worked for me with large files without reading the entire file first:

using(StreamReader sr = File.OpenText(txtBox_CSVFile.Text))
{
   var csvReader = new new CsvHelper.CsvReader(sr);
    while (csvReader.Read())
    {
         double progress = (double)sr.BaseStream.Position / sr.BaseStream.Length;
    }
}

it should work also with GetRecords, but I've not tested:

foreach(var record in csvReader.GetRecords<MyRecordClass>())
{
    double progress = (double)sr.BaseStream.Position / sr.BaseStream.Length;
}

I've checked your solution

foreach(var record in csvReader.GetRecords<MyRecordClass>())
{
    double progress = (double)sr.BaseStream.Position / sr.BaseStream.Length;
}

which didn't work for me.
But you can do this

foreach(var record in csvReader.GetRecords<MyRecordClass>())
{
    double progress = (double)csvReader.Context.CharPosition / csvReader.Context.CharsRead;
}

to get the desired result

Was this page helpful?
0 / 5 - 0 ratings