I'm doing a homework for my programming class, the following code is a part of my code which I cut out and formatted to be a 'runnable' program.
Now, if you run it you'll notice it creates a data.txt file, writing the amount of student IDs in the record as the first 4 bytes, and then it writes the student number (9 bytes) starting at byte 20 (the reason it starts at byte 20 is because the other unused 16 bytes are used for other data in my program... functions which I still have not coded. Each student will use up 244 bytes.

Now here is the problem: If you run the program again, the second studentID will be saved at the appropriate bytes but the previous ID is erased!

Hope someone can help me with this, thanks ;).

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#define tCLASSES 10

using namespace std;
int numRecords=0;
int classes;
int grades = 0;
int offset;

void checkRecords();
void writeNumber(std::string&);

int main(){
    string buff;
    
    againNum:
    // STUDENT NUMBER--------------------------------------------------
    cout << "Type the student's number : ";
    getline(cin, buff);
    if (buff.length()!=9){
       //system("cls");
       cout << "*** ID Number must be 9 characters long\n";
       goto againNum;
    }
    //STORE IN BIN FILE
    writeNumber(buff);
}


void writeNumber(string& buff){
     checkRecords();
     cout << "Offset = 4 + (" << numRecords << " * (44 + (" << tCLASSES << " * 24)))\n";
     offset = 4 + (numRecords * (44 + (tCLASSES*24)));
     cout << "Offset is " << offset << ".\n";
     ofstream semData("data.txt", ios::binary);
     semData.seekp(offset+16);
     cout << "Writing student number to bin file at " << semData.tellp() << "!\n";
     semData.write((buff.c_str()), 9);
     system("PAUSE");
     numRecords++;
     semData.seekp(0);
     cout << "Writing # of records (" << numRecords << ") to bin file at " << semData.tellp() << "!\n";
     semData.write(reinterpret_cast<char*>(&numRecords),4);
     semData.close();

}

void checkRecords()
{
     ifstream semData("data.txt", ios::binary);
     if (!semData.is_open())
     {
        semData.close();
        ofstream semData("data.txt", ios::binary);
        semData.close();
     }
     else
     {
         ifstream semData("data.txt", ios::binary);
         semData.read(reinterpret_cast<char*>(&numRecords), 4);
         cout << "There are " << numRecords << " students in the record.\n";
         semData.close();
     }
}

I guess thats because when you open your file the next time, you don't use the iostream flag append and thats the reason your previous contents get erased.

A file which already has contents when opened for writing needs to be opned in append mode for preserving the previous contents. More information and example here.

I guess thats because when you open your file the next time, you don't use the iostream flag append and thats the reason your previous contents get erased.

A file which already has contents when opened for writing needs to be opned in append mode for preserving the previous contents. More information and example here.

Yeah, I just noticed that I wasn't using the app flag. Now, changing

ofstream semData("data.txt", ios::binary);

to

fstream semData("data.txt", ios::out|ios::binary|ios::app);

makes things even worst. Data isn't written to the appropriate addresses.

What else am I supposed to add?
It would seem that the ios::nocreate flag is the one I need but it doesn't seem to be included in the standard libary... and I know there should be a way of doing these without the need of non-standard libraries.

Hopefully you or someone else will notice something else missing!

Thanks!

hmm I was expectin ios::ate to work instead of the append flag... but it didn't.

I added the ios::in flag to do some debugging while in the program and I noticed that it worked.

In other words, seems I needed the ios::in flag too... hmm it makes sense.

It would be easier to read youe header record, then read the number of students specified into a student array. After you add a new student to the array, recreate the file by outputting the header and all the students.

that might be easier to program, but it's not a desirable solution.
If the file gets larger it will inevitably be a LOT slower than modifying the existing file.
It could also easily lead to out of memory errors.

that might be easier to program, but it's not a desirable solution.
If the file gets larger it will inevitably be a LOT slower than modifying the existing file.
It could also easily lead to out of memory errors.

I see your point -- in a professional setting. But

I'm doing a homework for my programming class, ...

tells me your apprehension is unfounded and the OP may be using a technique beyond him at this time. I may be wrong, but it's worth pointing out.

void checkRecords(){
ifstream semData("data.txt", ios::binary);if (!semData.is_open()){
semData.close();
ofstream semData("data.txt", ios::binary);
semData.close();}else{
ifstream semData("data.txt", ios::binary);
semData.read(reinterpret_cast<char*>(&numRecords), 4);cout << "There are " << numRecords << " students in the record.\n";
semData.close();}}

I don't claim to be an expert but logically what if he opens up a file and it opened successfully, why does he open up the same file again? And if intentional where does he close it?

Edited 3 Years Ago by happygeek: fixed formatting

It wasn't intentional ;) , although it didn't cause any errors.
Thanks for pointing that out :) .

I see your point -- in a professional setting. But
tells me your apprehension is unfounded and the OP may be using a technique beyond him at this time. I may be wrong, but it's worth pointing out.

IMO you should start people by teaching them the right way to do things, rather than teaching them a quick hack now and later trying to explain that they were taught to do things incorrectly because the right way takes a few more lines of code.

This question has already been answered. Start a new discussion instead.