Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading CSV data from a file

Tags:

c++

I'm sorry if this has been asked, but I can't seem to find a solution that helps me. I'm trying to read in data from a text file, and ultimately store it in an object.

The text file has 4 variables all separated with commas.

I've tried to do this as follows:

string v1, v2, v3, v4;
ifstream afile;
afile.open("thefile.txt");
afile >> v1 >> v2 >> v3 >> v4;
afile.close();
cout << v1 << endl;
cout << v2 << endl;
cout << v3 << endl;
cout << v4 << endl;

The file has multiple records. I have tried to just do 1 for now to makes sure it works, but when it reads in the data, it doesn't separate at the commas.

From there, I want to store the data into an object. Will the following work: Thing* thing1 = new Thing(v1, v2, v3, v4);

Although, when I read in say 5 records, what would be the best way to structure the above line of code? As each object needs a unique name, is there a way I could iterate perhaps using a for loop and a vector? ie for (int i = 0; i < 5; i++) { // read in data // store in vector }

Any hints are very much appreciated

like image 368
CocaCola Avatar asked Sep 02 '12 05:09

CocaCola


Video Answer


2 Answers

The CSV format is more complicated than just a comma separator. It can contain quotation marks that you should escape and interpret accordingly and diverse separators may be allowed. You really should use a dedicated CSV import / export library if your input file is not strictly formatted.

A tokenizer class may answer your question (such as the one from boost or simpler ones are available).

You should check the other questions about this subject.

like image 95
Soravux Avatar answered Oct 19 '22 17:10

Soravux


Heed @Soravux answer and use a specialized library if you can. In particular, the strtk toolkit that he suggests seems interesting and is just a single header. Boost can also do it in at least 5 different ways, and is a library worth learning if you are going to use C++ for some time. That said, all those solutions will add some complexity to your program, and chances are that you want to spend that effort somewhere else, specially if all you need is a very simple number-reader. Here is how to go in standard C++ (with STL, e.g., vector and streams):

    #include <iostream>
    #include <sstream>
    #include <fstream>
    #include <string>
    #include <algorithm>
    #include <vector>

    using namespace std;

    vector<double> &split(const string &s, 
        char delim, vector<double> &elems) 
    {
        stringstream ss(s);
        string item;
        while (std::getline(ss, item, delim)) {
            stringstream conv( item );
            double number;
            conv >> number;
            elems.push_back(number);
        }
        return elems;
    }

    struct my_record_t{
        double f1, f2, f3, f4;
    };

    typedef vector<my_record_t> my_record_vector_t;

    int main( int argc, char* argv[])
    {
        stringstream  in("10,20,2.0,5\n"
                          "4.,5.,6.,80\n"
                          "4.,2.,6.,70\n"
                          "4.,5.,6.,86\n"
                          "2.,5.,9.,80\n");
        // Or alternatively, :
        //    ifstream in("myfile.csv");

        // Here you store your records
        my_record_vector_t mrv;

        string line;
        vector< double > numbers; 
        while( std::getline( in, line, '\n' ) )
        {
            numbers.clear();
            split( line, ',', numbers);
            my_record_t r;
            r.f1 = numbers[0];
            r.f2 = numbers[1];
            r.f3 = numbers[2];
            r.f4 = numbers[3];
            mrv.push_back( r );
        }

        cout << mrv.size() << " records read" << endl;


        return 0;
    }

A bit too long maybe, but it can save your day.

like image 43
dsign Avatar answered Oct 19 '22 17:10

dsign