Scripts: Simplest CSV file reader

 

Simplest CSV file reader:

Provide simplest class to read and parse CSV file

Author: Denis Kislicyn

 
Nice solution. Will be great to add methods of sorting and finding values in
 
Automated-Trading:

Simplest CSV file reader:

Author: Denis Kislicyn

Thanks. How do you think what kind of sorting and searching values will be useful? Could you explain, please.

 

Hey mate,


Great work!

Thank you for making, and sharing, this library.


I did found a logical bug in your code-

If reading a csv file without a header,

Your reader will read file as having only 1 column (well, technically 0 columns), regardless of how many columns are actually there.


DKSimplestCSVReader.mqh line 76-

if(!(aHasHeader && HeaderString == ""))
{
   CArrayString* Row = new CArrayString;
   for(int i = 0; i < ArraySize(lineFields); i++)
      Row.Add(lineFields[i]);
      Rows.Add(Row);
}
else
{
   HeaderString = fileLine;
   for(int i = 0; i < ArraySize(lineFields); i++)
      Columns.Add(lineFields[i], i);
}

So if aHasHeader is false, the 'else' clause will never be called, and the 'Columns' HashMap will remain 0/empty.


EDIT-

Not the most elegant solution,

But just at the top of my head,

You can add something like the following, inside the 'if' clause-

if(!aHasHeader && Columns.Count() == 0) {

   for(int i = 0; i < ArraySize(lineFields); i++)
      Columns.Add("Column " + (string)(i+1), i);
}

I haven't compiled the above, so it might need some syntax adaptations.

Also, it is very late, so I'm not that focused, so I can't recall if MQL accepts the sort of string concatenation I've made in the above code.


Cheers.

 
AMI289 #:

Hey mate,


Great work!

Thank you for making, and sharing, this library.


I did found a logical bug in your code-


Thanks for the bug report. I gonna check it.

 
AMI289 #:


So if aHasHeader is false, the 'else' clause will never be called, and the 'Columns' HashMap will remain 0/empty.

I've checked the class code. For no-columns CSV files, the column list shouldn't be filled. Because, there're no headers in the file. The first line of the file contains data, but not columns name. So, parsing to fill columns list, as you suggested, is incorrect for no-header files.

Also retrieving data after reading no-header file is not possible using CSVFile.GetValue(i, "Time") method with the column name. It returns error_value in this case. But  CSVFile.GetValue(i, 0) by field index works well always.

 
This works perfectly.
 
string Filename = "filename.csv"; CDKSimplestCSVReader CSVFile; // Create class object // Read file pass FILE_ANSI for ANSI files or another flag for another codepage. // Give values separator and flag of 1sr line header in the file if (CSVFile.ReadCSV(Filename, FILE_ANSI, ";", true)) { PrintFormat("Successfully read %d lines from CSV file with %d columns: %s", CSVFile.RowCount(), // Return data lines count without header CSVFile.ColumnCount(), // Return columns count from 1st line of the file Filename); // Print all columns of the file from 1st line for (int i = 0; i < CSVFile.ColumnCount(); i++) { PrintFormat(" Column Index=#%d; Name=%s", i, CSVFile.GetColumn(i)); } // Print values from all rows for (int i = 0; i < CSVFile.RowCount(); i++) { PrintFormat("Row %d: Value by column name: CSVFile.GetValue(i, ""Time"")=%s", i, CSVFile.GetValue(i, "Time")); // Get value from i line by column name PrintFormat("Row %d: Value by column index: CSVFile.GetValue(i, 0)=%s", i, CSVFile.GetValue(i, 0)); // Get value from i line by column index } } else PrintFormat("Error reading CSV file or file has now any rows: %s", Filename);
 
Wow! Thank you so much for this, beyond helpful!
Reason: