views:

164

answers:

3

Hi,

I am having lots of troubles trying to read a file in C++. The main problem I'm having is reading properly the first line of the stream since it is different from all the other lines.

A sample file would be:

#Newbie 101|Exam 1|3
Person One|10
Person Two|20
Person Three|30

the first line starts with a # and declares the class name, assignmanet name and total students.

void Grading::loadData()
{
    string filename;
    cout << "Enter a filename with records to open: ";
    cin >> filename;

    std::ifstream file;
    file.open(filename.c_str(), std::ios::app);

    if (!file) {
        cout << "Unable to open the specified file" << endl;
        return;
    }

    string buffer;
    vector<Student> students;
    vector<Student>::iterator it;

    while (!getline(file, buffer, '|').eof()) {

        Student stud;
        string name;
        string tmpgrade;
        string course;
        string assignment;
        int totalstudents;

        // read first line
        if (buffer.find("#") == 0) {
            getline(file, course, '|');
            cout << "Course Name    : " << course << endl;
            cout << "Grading Item   : " << assignment << endl;
            cout << "Total Students : " << totalstudents << endl;
            cout << endl;
            continue;
        }


        getline(file, name, '|');
        getline(file, tmpgrade, '|');

        double grade = strtod(tmpgrade.c_str(), NULL);

        stud.name = name;
        stud.grade = grade;

        cout << "Name: " << stud.name << endl;
        cout << "Grade: " << stud.grade << endl;

        students.push_back(stud);

    }

I really appreciate any suggestions on how to fix this code to read properly the file. Thanks a lot in advance!

+2  A: 

Sounds like the reading / parsing of the first line should be outside (above) your loop. Then you will not have to worry about parsing 2 different types of lines in your main loop body.

Brian R. Bondy
A: 

You just need to handle the first line separately as a special case. You could do this by reading in the first line (of course checking that there is a first line) outside the main loop or handling inside the loop for the special case, using a boolean or a line count.

NoahD
A: 

From my point of view you are in the wrong way to do what you want.

LoadData() will read token stopping each time it reads the '|' delimiter. When finding the "#Newbie 101" token it will discard it as it begins with # character. The next iteration in its loop it will handle "Exam 1" token (next one .. on the first line!!).Well ok. And then the next iteration, it reads the next one which is "3 \nPerson one". Please note the end of line character in the middle of the string! Considering the output, I am not sure it is what you want, huh?

AFAI understand, the behavior you want is your program to skip commented lines (begining with # character). As a solution, you'd better read a whole line instead with getline(file_handle, line) in a first loop. Do not specify any '|' character as the third parameter when calling getline(), '\n' must be taken as the delimiter to get the whole line.

In this first loop, add a first check to see whether a "#" character begins the line. If so , call the continue statement. Otherwise enter in a second nested loop to interpret all tokens in your line, this time using find_first_of() string's method to find the '|' character. Loop until you read the whole line.

You could either considering BOOST tokeniser lib. While I've never used it (or a very long time ago when I was sudent), I remember it was quite appropriated to do that kind of job in a very simple way! I believe there are also good libs to read a file and discard commented lines. Maybe in BOOST ... (That's a shame I really have to get a deeper look in this lib ...)

yves Baumes
Have a quick look in the Boost website, you could use tokeniser lib, or the split() algorithm in the string lib to get your goal
yves Baumes