Reputation: 521
I have a text file which lists certain attributes of an object class like DVD title(string) category(string) price(int) runtime(int) year released(int)
the file is listed like
Movie1
Action
10.45
123
2008
Movie2
Sc-fi
12.89
99
2008
I have a function whereby you type in the name of the file and it is supposed to read in the different attributes into an object
DVD* file(DVD arr[], string fileName, int s, int& e)
{
ifstream file(fileName);
DVD j;
string v;
string w;
double x;
int y;
int z;
while(!file.eof())
{
file >> v;
j.setTitle(v);
file >> w;
j.setCategory(w);
file >> x;
j.setPrice(x);
file >> y;
j.setRuntime(y);
file >> z;
j.setYear(z);
arr=add(arr, j, s, e); //this is just a function that adds the object to an arry
}
file.close();
return arr;
}
but it is not working correctly, I want it to read each line into the variable, then if there is a space skip it, but if not the end of file keep reading until it hits a string. Any suggestions?
Upvotes: 0
Views: 134
Reputation: 90543
Two things.
Firstly:
while(!file.eof())
is broken eof()
doesn't return true
until after a read is attempted.
The second thing is that if you want to read line by line, it is better to use something like this:
void read_file(std::vector<DVD> & arr, string fileName) {
ifstream file(fileName.c_str());
DVD j;
std::string line;
enum State {
TITLE, CATEGORY, PRICE, RUNTIME, YEAR
} state = TITLE;
while(std::getline(file, line)) {
// if we encounter an empty line, reset the state
if(line.empty()) {
state = TITLE;
} else {
// process the line, and set the attribute, for example
switch(state) {
case TITLE:
j.setTitle(line);
state = CATEGORY;
break;
case CATEGORY:
j.setCategory(line);
state = PRICE;
break;
case PRICE:
j.setPrice(boost::lexical_cast<double>(line));
state = RUNTIME;
break;
case RUNTIME:
j.setRuntime(boost::lexical_cast<int>(line));
state = YEAR;
break;
case YEAR:
j.setYear(boost::lexical_cast<int>(line));
arr.push_back(j);
state = TITLE;
break;
default:
// just in case
state = TITLE;
break;
}
}
}
}
This works because std::getline
returns a reference which when used in a boolean context will be true
if the last operation left the stream in a "good" state.
In this example, I am using boost::lexical_cast<>
to convert a string to a numeric type as needed, but you can use std::stringstream
to do this manually, or any other method you feel works best for you. For example, atoi()
, strtol
, strtod
, etc.
SIDE NOTE: it is far better to use std::vector<DVD>
instead of a native array. It will be just as fast, but will properly handle resizing and cleanup for you. You will no longer have a need for your add
function since you will be able to just do: arr.push_back(j);
Upvotes: 1