Ido Sorozon
Ido Sorozon

Reputation: 83

Updating the end of the file in c++ fstream

I wrote this code:

#include <fstream>
#include <iostream>

using namespace std;

struct Man
{
    int  ID;
    char Name[20];
};

void Add();
void Update();
void Print();

int main()
{
    int n;

    cout << "1-add, 2-update, 3-print, 5-exit" << endl;
    cin >> n;

    while (n != 5)
    {
        switch (n)
        {
            case 1: Add(); break;
            case 2: Update(); break;
            case 3: Print(); break;
        }

        cout << "1-add, 2-update, 3-print, 5-exit" << endl;
        cin >> n;
    }
    return 0;
}

void Add()
{
    fstream file;

    file.open("Data.dat", ios::in | ios::out | ios::binary);

    if (file.is_open())
    {
        int  id;
        Man  man;
        bool didFound = false;

        cout << "ID  : ";
        cin >> id;

        file.read((char*)&man, sizeof(Man));

        while (!file.eof() && !didFound)
        {
            if (man.ID == id)
            {
                cout << "Already exist" << endl;
                didFound = true;
            }

            file.read((char*)&man, sizeof(Man));
        }

        if (!didFound)
        {
            man.ID = id;
            cout << "Name: ";
            cin >> man.Name;

            file.clear();
            file.seekp(0, ios::end);
            file.write((char*)&man, sizeof(Man));
        }
    }
}

void Update()
{
    fstream file;

    file.open("Data.dat", ios::in | ios::out | ios::binary);

    if (file.is_open())
    {
        int  id;
        Man  man;
        bool didFound = false;

        cout << "ID  : ";
        cin >> id;

        file.read((char*)&man, sizeof(Man));

        while (!file.eof() && !didFound)
        {
            if (man.ID == id)
            {
                cout << "Name: ";
                cin >> man.Name;

                file.seekp((int)file.tellg() - sizeof(Man), ios::beg);
                file.write((char*)&man, sizeof(Man));

                didFound = true;
            }

            file.read((char*)&man, sizeof(Man));
        }

        file.close();

        if (!didFound)
        {
            cout << "Cant update none existing man" << endl;
        }
    }
}

void Print()
{
    fstream file;

    file.open("Data.dat", ios::in | ios::binary);

    if (file.is_open())
    {
        int  id;
        Man  man;
        bool didFound = false;

        cout << "ID\tName" << endl;

        file.read((char*)&man, sizeof(Man));

        while (!file.eof())
        {
            cout << man.ID << '\t' << man.Name << endl;

            file.read((char*)&man, sizeof(Man));
        }

        file.close();
    }
}

But I have a problem in Update function: When I update the last Man in the file, when it reach file.read the file writes the value of the last Man(in the file before the writting) to the end of the file (after the updated man)

I added this after file.write and it seems to solve it:

file.seekg(file.tellp(), ios::beg);

Can somebody explain why?

(yes it can be solved with else)

Upvotes: 4

Views: 1829

Answers (1)

Potatoswatter
Potatoswatter

Reputation: 137940

Somewhat arbitrarily, you are required to perform seek in between read and write. It's not spelled out in the Standard, but the C++ Standard mentions that C++ fstream has the same properties as C stdio streams with respect to the validity of stream operations, and the C standard mentions that a positioning command is required between reading and writing (or vice versa).

Some platforms relax the requirement. GCC after about version 4.5 or 4.6, I personally modified basic_filebuf to eliminate the byzantine rule.

By the way, file.seekg( 0, ios::cur ) is safer.

Upvotes: 4

Related Questions