Cirrus
Cirrus

Reputation: 41

C++ Reading text file into struct data members

I'm currently trying to load a text file into struct data members. Each number is separated by a comma.

#include<string>
#include<sstream>

using namespace std;

struct server{
    bool isBusy;
};

struct pass{
    double arrivalTime = 0;
    double serviceTime = 0;
    int classType = 0;
};

int main(){

    string fileName;
    string line;
    pass Pass;

    cout << "Enter file name: ";
    cin >> fileName;

    ifstream fin(fileName);

    while (getline(fin, line, ','))
    {
        /*NEED HELP HERE*/
        fin >> Pass[0].arrivalTime;
        fin >> Pass[0].serviceTime;
        fin >> Pass[0].classType;
    }
}

Here is an example of the text file.

0.951412936,2.131445423,0
1.902743503,2.010703852,0
2.537819984,2.326199911,0
3.425838997,1.603712153,0
3.502553324,0.998192867,0
3.917348666,1.49223429,0
4.391605986,0.831661367,0
4.947059678,0.8557003,0
5.429305232,2.42029408,0

The data in the text file follows this format:

arrivalTime,serviceTime,classType

As you can see i have split the line up and stored it in "line" using the comma delimiter, but i am unsure how to load each number into the struct in the while loop.

Any help would be appreciated.

Upvotes: 1

Views: 9315

Answers (5)

alessandro mercadante
alessandro mercadante

Reputation: 375

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

using namespace std;

struct server{
    bool isBusy;
};

struct pass{
    double arrivalTime;
    double serviceTime;
    int classType;
    friend std::istream & operator >>(std::istream &in, pass &p) {
        char c;
        in >> p.arrivalTime >> c >> p.serviceTime >> c >> p.classType;
        return in;
    }
};

int main(){

    string fileName;
    string line;
    cout << "Enter file name: ";
    cin >> fileName;

    ifstream fin(fileName.c_str(), ifstream::in);
    vector<pass> passes;
    pass Pass;

    while (fin>>Pass)
      passes.push_back(Pass);

    for(vector<pass>::const_iterator iter = passes.begin(); 
    iter != passes.end();
    ++iter)
      std::cout<<iter->arrivalTime<<" "<<iter->serviceTime<<" "
      <<iter->classType<<std::endl;

}

Upvotes: 1

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

This loop is wrong:

while (getline(fin, line, ','))
{
    /*NEED HELP HERE*/
    fin >> Pass[0].arrivalTime;
    fin >> Pass[0].serviceTime;
    fin >> Pass[0].classType;
}

You are reading everything from the stream up to the next ',' character, then trying to read more from the stream.

Given the input file:

0.951412936,2.131445423,0
1.902743503,2.010703852,0
2.537819984,2.326199911,0

Your program reads "0.951412936" into line (and discards the ',') then tries to read the next input into Pass[0].arrivalTime but the next input is 2.131445423, which was meant to be the serviceTime (which you already read into line).

As Shreevardhan suggests you can define an operator for reading your struct from a stream. I would make it more reliable like so:

struct ExpectedChar { char expected; };

// read a character from a stream and check it has the expected value
std::istream& operator>>(std::istream& in, const ExpectedChar& e)
{
  char c;
  if (in >> c)
    if (c != e.expected)  // failed to read expected character
      in.setstate(std::ios::failbit);
  return in;
}

// read a struct pass from a stream
std::istream& operator>>(std::istream& in, pass& p)
{
  ExpectedChar comma{ ',' };
  in >> p.arrivalTime >> comma >> p.serviceTime >> comma >> p.classType;
  return in;
}

This will stop reading if the input file does not meet the expected format. Now you can do:

while (fin >> Pass)
{
  // do something with each pass
}
if (!fin.eof())  // stopped reading before end-of-file
  throw std::runtime_error("Invalid data in input file");

This will keep reading a pass from the file until reading fails, either because it reached the end of the file, or because there was some bad data in the file. If there is bad data it throws an exception.

Upvotes: 1

wangke1020
wangke1020

Reputation: 249

while (getline(fin, line))
{
    sscanf(line.c_str(), "%lf,%lf,%d", &arrivalTime, &serviceTime, &classType);
}

Upvotes: 1

Shreevardhan
Shreevardhan

Reputation: 12641

Define an istream operator >> for your struct. Something like

struct pass {
    double arrivalTime = 0;
    double serviceTime = 0;
    int    classType   = 0;

    friend std::istream & operator >>(std::istream & in, pass & p) {
        char c;
        in >> p.arrivalTime >> c >> p.serviceTime >> c >> p.classType;
        return in;
    }
};

Then, simply

pass Pass;
fin >> Pass;

Upvotes: 2

POTEMKINDX
POTEMKINDX

Reputation: 395

Here is hint;

string line;
string temp;            
string::size_type sz;
while (getline(cin, line))   
{
    istringstream ss( line );
    getline( ss, temp, ',' );  
    double arrivalTime = stod(temp, &sz);
    getline( ss, temp, ',' );  
    double serviceTime = stod(temp, &sz);
    getline( ss, temp, ',' );  
    double classType = stod(temp, &sz);

    cout << arrivalTime << ' ' 
         << serviceTime << ' ' 
         << classType   << endl;
}

Upvotes: 0

Related Questions