1

I literally ran out of ideas. All I want is to read and write from and to a binary file into a class that I created.

int ClientData::readClientDat(ClientData * client_block)
{
    int clientData_SIZE;

    ifstream inClients;
    inClients.open("D:\\Programming\\Qt\\bookstore instances\\bookstore_system\\data\\clients.dat", ios::binary);
    clientData_SIZE = static_cast<int>(inClients.tellg());
    client_block = new ClientData [clientData_SIZE+1];
    if (inClients.is_open())
     {
        for(int i = 0; i <clientData_SIZE; i++)
        {
//                inClients.read((char *)&client_block[i].user, sizeof(client_block[i].user));
//                inClients.read((char *)&client_block[i].pass, sizeof(client_block[i].pass));
//                inClients.read((char *)&client_block[i].mail, sizeof(client_block[i].mail));
//                inClients.read((char *)&client_block[i].id, sizeof(client_block[i].id));
            inClients.read((char *)(&client_block[i]), sizeof(ClientData));
        }
        inClients.close();
     }
    return clientData_SIZE;
}

It doesn't read correctly for some reason and I guessed I had something wrong with the writing function

void ClientData::insertNewClient(ClientData newUser)
{
    ofstream outClients;
    outClients.open("D:\\Programming\\Qt\\bookstore instances\\bookstore_system\\data\\clients.dat", ios::binary | ios::app);  // write the new client's data in the database.
    int clientData_SIZE = outClients.tellp();
    newUser.id = (clientData_SIZE) + 1;

//    ClientData * client_block;
//    client_block[clientData_SIZE] = newUser;

    outClients.write((char *)(&newUser), sizeof(ClientData));

    outClients.close(); //-----------------------------------------closes file.
}

What should I do?

Here's my class

class ClientData
{
public:
    ClientData();

    int readClientDat(ClientData * client_block);
    ClientData enter_activeUser(QString QUser, QString QPass, QString QMail);
    bool isAdmin(ClientData user);
    bool userExists(ClientData newClient);
    int isClient(ClientData &user);
    void insertNewClient(ClientData newUser);

private:

    char user[32];
    char pass[32];
    char mail[32];
    int id;
};
11
  • 1) Write a proper serialization function. 2) What do you expect client_block = new ClientData [clientData_SIZE+1]; to do? Commented Jun 14, 2021 at 17:43
  • @spectras 1) I'm sorry but I'm new. What's a serialization function? 2) I expected it to create an object array to store the data from the file Commented Jun 14, 2021 at 17:47
  • 1) it was not intended as criticism but as a helpful suggestion, sorry that my wording did not make it clear. In your very specific, limited scope, you can skip the serialization and just write like you do, but for most objects this will not work — a serialization function is a function that takes an object and writes its content out as a series of bytes, thus the name. Eg here it would take a ClientData and write user, pass, mail and id one by one, in the format of your choosing). Commented Jun 14, 2021 at 17:55
  • Pop quiz: 1) What do you expect to get from tellg() immediately after opening your file? 2) And how does the number of bytes in the file translate to the number of records to be read from the file? Hint: both are trick questions. Commented Jun 14, 2021 at 17:57
  • 2) Well the new ClientData[clientData_SIZE+1] part does that, yes (though you will want to check the value of clientData_SIZE, you'll have a surprise). Now, what does the client_block = part do? Or, said another way: how do you expect the caller to get that array? Commented Jun 14, 2021 at 17:57

1 Answer 1

1

Ok, this post is gonna be big, but I hope I'll address at least all the major issues.

First: You should't write the whole class to a file and expect it to work, this is usually ok with POD types but not with C++ classes.

Second: The read function receives a pointer by value, and then leaks the memory that was allocated.

Now, let's start with the read function:

clientData_SIZE = static_cast<int>(inClients.tellg());

This is cleary going to return zero, because you are at the beginning of the file. You need to seek to the end of the file and only then get the pointer's position (see example at the end of the post).

This code:

inClients.read((char *)(&client_block[i]), sizeof(ClientData));

Don't expect it to work, even if you get right the size of the file and the number of iterations. Classes are not POD types, they have constructors, destructors, methods, possibly a vtable. Stuff that cannot be memcpy'ed.

Now with the write function:

int clientData_SIZE = outClients.tellp();

This is going to be the number of bytes in the file, not the number of clients! If you want the number of clients you should divide by sizeof(ClientData)) but, as I said before, it is not advisable to write the class to the file.

And now comes the concept of serialization: Serialization allows to transfer data from one point to the other as it was a simple copy. You need to write code to support that.

You could implement the functions write(ostream&) and read(istream&) or overload the stream operator:

class ClientData {
    
    // ...
    
    friend ostream& operator<<(ostream &out, const ClientData &c);
    friend istream& operator>>(istream &in,  ClientData &c);
};

// ok this is a hack, but it works as an example
#define CLIENT_DATA_SIZE (32+32+32+4)

ostream& operator<<(ostream& os, const ClientData& cd) {
    os.write(cd.user, sizeof(user));
    os.write(cd.pass, sizeof(pass));
    os.write(cd.mail, sizeof(mail));
    os.write(&cd.id, sizeof(id))
    return os;
}

istream& operator>>(istream &in, ClientData &cd) {
    in.read(cd.user, sizeof(user));
    in.read(cd.pass, sizeof(pass));
    in.read(cd.mail, sizeof(mail));
    in.read(&cd.id, sizeof(id));
    return in;
}

Then the read function should look like this:

// note this changed to pointer to pointer (you can also pass the pointer by reference)
int ClientData::readClientDat(ClientData **client_block)
{
    int clientData_SIZE;

    ifstream inClients;
    inClients.open("D:\\Programming\\Qt\\bookstore instances\\bookstore_system\\data\\clients.dat", ios::binary);
    if (inClients.is_open())
    {
        inClients.seek(0, inClients.end);
        clientData_SIZE = static_cast<int>(inClients.tellg()) / CLIENT_DATA_SIZE;

        // dont forget to relese the pointer (with delete[]) when finished
        client_block = new ClientData [clientData_SIZE];

        for(int i = 0; i <clientData_SIZE; i++)
        {
            clientData_SIZE >> client_block[i];
        }
        inClients.close();
    }
    return clientData_SIZE;
}

And the write function:

void ClientData::insertNewClient(ClientData newUser)
{
    ofstream outClients;
    outClients.open("D:\\Programming\\Qt\\bookstore instances\\bookstore_system\\data\\clients.dat", ios::binary | ios::app);  // write the new client's data in the database.
    int clientData_SIZE = outClients.tellp() / CLIENT_DATA_SIZE;
    newUser.id = (clientData_SIZE) + 1;
    
    outClientes << newUser;

    outClients.close(); //-----------------------------------------closes file.
}

Note that I am no checkings for errors, you may want to check whether read, writes and open return ok.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.