Thy Gamosh
Thy Gamosh

Reputation: 77

Inconsistencies in file I/O

I have a data type that takes ID and Record location. The file contains around 1000 item, each contain id, first name, last name, GPA (each item total of 25 characters) My program seeks 25 characters for each loop, takes just the ID, put the ID and the record number in the table, etc..

Then, the user inputs the id, I retrieve the item from the table based on the given id, after that I get the record number, seek the item in the file, and then read the details.

Provided the headers of the recordlocation and the arrayhashtable classes, some stuff were removed to make it shorter

class  RecordLocation{
public:    
    RecordLocation(int idd = -1, int rno = -1);     
    void setId(int);
    int  getId();
    void setRNo(int);
    int getRNo();
    int Hash();    
    int LinearRehash(int initial_hash_value);           
private:
    int id;
    int r_no;
};

/

    typedef RecordLocation ItemType;
    class  ArrayHashTable{  //declares a class data type

    public:
        ArrayHashTable();//Fill info with null studnets
        Error_Code RetrieveItem(ItemType&  item, bool&  found);
        Error_Code InsertItem(ItemType  item);
        Error_Code DeleteItem(ItemType  item);
        void PrintAllItems();
    private:
        ItemType info[MAX_ITEMS];
        int items;
    };

/ data.txt short version

4609:hhhhh    hhhhh   :2:4737:ggggg    ggggg   :4:5530:rrrrr    rrrr   :4:4849:ttttttt tttttttttt:2:5563:ddddd    dddd    :2:4959:aaaa    aaaaaaa  :4:

/

void main(){    
    char buffer[26] = { '0' };
    char id_buff[5];
    int id;
    ArrayHashTable object;
    RecordLocation temp;
    ifstream input("data.txt");
    if (!input){
        cout << "Unable to open file " << endl;
        exit(1);
    }

    int i = 0;
    int c;

//location 1    
    do{
        input.seekg(25 * i);
        input.read(id_buff, 4);
        id = convert(id_buff);

        temp.setId(id);
        temp.setRNo(i);
        object.InsertItem(temp);

        i++;

    }while (input);

//location 2        

    input.close();      
}

Now what is baffling is with the following statement:

input.seekg(25 * 3);//3 is arbitrary
    input.read(buffer, 25);
    cout << buffer << endl;

If it is to be placed in location 1, then it is normal output. If it is in location 2 then the output is 0. if it is both in location 1 and 2, then both output is normal.

One way to solve this is to finish the do while statement, and then close the file and open it again, perform the statement and it is all normal. But this isn't an informed solution.

What I'm basically saying is that I'm done reading the file, and after that it seems that I can't get any more information out of it. I also did not add that part to ask the user for ID (to make it simpler)

Upvotes: 0

Views: 85

Answers (2)

rici
rici

Reputation: 241861

If any call to input.read fails, your program never notices, because you never check the return code of the read method. So we have to work out what happened, rather than seeing it. Fortunately, that's not too difficult in this case but in general you will find life to be easier if you get into the habit of checking for error returns.

We know that when Location 2 is reached, input's failbit is set. That must be true, because the while loop doesn't exit until input is false.

Since the failbit is set, neither the seekg nor the read do anything useful. The stream position is not modified, no data is read and the buffer is unmodified.

So when the program sends buffer to std::cout, what it is sending is whatever was previously in buffer. If the code shown is at Location 1, then the fourth record will still be in buffer. Otherwise, buffer will contain a single '0' followed by NULs, since it was initialized to that. (0 and '0' are not the same.)

That perfectly explains the observed behaviour. Before you do the seekg, you need to clear input's failbit.


In fact, the while loop is also incorrect. After the last entry is read, input will still be good, and the loop will repeat. The read will then fail, leaving id unmodified but since you don't check, the program wiil contnue, using the bogus id. Now 'input' is false and the parse fails.

What you need to do is exit the loop if either the read or the seekg fail. The explicit test of the boolean conversion of input is completely unnecessary and not useful because it comes too late.

Upvotes: 1

The Dark
The Dark

Reputation: 8514

According to cplusplus.com, for C++98:

If the eofbit flag is set before the call, the function fails (sets failbit and returns).

So once you have hit the end of the file, the EOF (end of file) bit is set and needs to be reset before using this function.

Note that for C++11:

The function clears the eofbit flag, if set before the call.

So, you could try a newer compiler, or clear the eof flag using clear, e.g.:

input.clear();

Upvotes: 1

Related Questions