如何用C++将二进制文件读取到类数组中



我的想法真的用完了。我只想从一个二进制文件中读取和写入我创建的类。

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;
}

由于某种原因,它读不正确,我猜我的书写功能出了问题

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.
}

我该怎么办?

这是我的班级

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;
};

好吧,这篇文章会很重要,但我希望我至少能解决所有的主要问题。

首先:你不应该把整个类写到一个文件中并期望它能工作,这通常适用于POD类型,但不适用于C++类。

第二:读取函数按值接收指针,然后泄漏分配的内存。

现在,让我们从读取功能开始:

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

这显然会返回零,因为您处于文件的开头。您需要seek到文件的末尾,然后才能获得指针的位置(请参阅文章末尾的示例(。

此代码:

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

不要指望它能起作用,即使你正确地确定了文件的大小和迭代次数。类不是POD类型,它们有构造函数、析构函数、方法,可能还有vtable。无法记忆的东西。

现在有了写功能:

int clientData_SIZE = outClients.tellp();

这将是文件中的字节数,而不是客户端数!如果您想要客户端的数量,您应该除以sizeof(ClientData((,但是,正如我之前所说,不建议将类写入文件。

现在出现了序列化的概念:序列化允许将数据从一个点传输到另一个点,就像它是一个简单的副本一样。您需要编写代码来支持这一点。

您可以实现函数write(ostream&)read(istream&),也可以重载流运算符:

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;
}

然后读取功能应该是这样的:

// 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;
}

以及写入功能:

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.
}

注意,我没有检查错误,你可能想检查读、写和打开是否返回正常。