CPP 将类写入/读取到二进制文件中
Posted
技术标签:
【中文标题】CPP 将类写入/读取到二进制文件中【英文标题】:CPP write/read class into binary file 【发布时间】:2021-10-18 08:53:43 【问题描述】:我有 3 个文件,main.cpp(主程序)、user.h(用户类)和 userlist.h(用于存储用户的 LinkedList 数据结构)。
我想创建一个程序来将用户存储和读取到二进制文件中。我的问题是当我运行下面的 main.cpp(第一次运行)来保存和读取文件时,它会读取并显示正常数据。但是当我运行main.cpp(第二次运行)只读取刚刚保存的文件时,它不能正常工作。
我不知道为什么会发生这种情况。我的用户类属性类型是 char*、char* 和 bool。
// main.cpp (first run)
UserList userList;
User user1("admin", "root", 1);
User user2("aaaa", "dcasf", 1);
User user3("user3", "abcd", 0);
User user4("user4", "bbbb", 0);
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.saveFile("user.txt");
userList.loadFile("user.txt");
userList.display();
// main.cpp (second run)
UserList userList;
userList.loadFile("user.txt");
userList.display();
// userlist.h
#ifndef USERLIST_H
#define USERLIST_H
#include "user.h"
using namespace std;
struct UserNode
User user;
UserNode* next = NULL;
UserNode()
UserNode(User user)
this->user = user;
UserNode(User user, UserNode* next)
this->user = user;
this->next = next;
;
class UserList
public:
UserList()
size = 0;
isEmpty = true;
head = NULL;
;
UserList(const UserList& userList);
~UserList()
clearAll();
void add(User user)
if(head == NULL)
head = new UserNode();
head->user = user;
else
UserNode* temp = head;
while(temp->next != NULL)
temp = temp->next;
temp->next = new UserNode();
temp->next->user = user;
void clearAll()
while(head != NULL)
UserNode* temp = head;
head = head->next;
delete temp;
head = NULL;
User find(string username)
UserNode* temp = head;
while(temp != NULL)
if(temp->user.getUsername() == username)
return temp->user;
temp = temp->next;
User user;
return user;
bool contain(string username)
UserNode* temp = head;
while(temp != NULL)
if(temp->user.getUsername() == username)
return true;
temp = temp->next;
return false;
void display()
UserNode* temp = head;
while(temp != NULL)
cout << temp->user.getUsername() << "\t" << temp->user.getPassword() << "\t" << temp->user.getIsAdmin() << endl;
temp = temp->next;
void saveFile(string filename)
ofstream output;
output.open(filename, ios::out | ios::binary);
UserNode* temp = head;
while(temp != NULL)
User user = temp->user;
output.write((char*)&user, sizeof(user));
temp = temp->next;
output.close();
void loadFile(string filename)
clearAll();
ifstream input;
input.open(filename, ios::in | ios::binary);
User user;
while(input.read((char*)&user, sizeof(user))) // read 1 user from file
add(user);
input.close();
private:
int size;
bool isEmpty;
UserNode* head;
;
// user.h
#ifndef USER_H
#define USER_H
using namespace std;
class User
public:
User()
User(char* username, char* password, bool isAdmin)
this->username = username;
this->password = password;
this->isAdmin = isAdmin;
~User()
void setUsername(char* username)
this->username = username;
void setPassword(char* password)
this->password = password;
char* getUsername()
return username;
char* getPassword()
return password;
bool getIsAdmin()
return isAdmin;
private:
char* username;
char* password;
bool isAdmin;
;
#endif
【问题讨论】:
保存到文件的指针在读回时不太可能指向有效对象(除非您在写入后立即执行此操作,而这些对象仍然存在)。您需要阅读“序列化”。 @molbdnilo 但是我运行另一个具有相同上下文的程序,将 Box 类对象保存在文件中并在单独的运行时将其读回。它工作正常。 但是你的Box
类与显示的代码有什么关系?它有指针数据成员吗?
@john 可能是因为您的 Box
类只包含数字或数组,而没有指针。 (但是你不能通过观察 C++ 程序的行为来判断它是否正确 - 未定义的行为可能会出于所有错误的原因做你所期望的。)
您的选项与已经提到的相同:1)不使用指针,或 2)实现正确的序列化。
【参考方案1】:
当你写入文件时,它会清除已经写入的数据。您应该使用附加模式写入文件
【讨论】:
我的问题不是那个。我的问题是,当我保存到文件中并在程序运行时读取文件时,它可以正常工作。但是当我只运行readFile()读取刚才保存的文件时,就不能正常工作了。【参考方案2】:我认为你序列化一个带有 char 指针的结构的方式,只序列化 char 指针的地址。我们必须携带字符串的长度并用这个长度信息序列化每个字符串,以便我们可以准确地反序列化结构。
// userlist.h
#ifndef USERLIST_H
#define USERLIST_H
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "user.h"
using namespace std;
struct UserNode
User user;
UserNode* next = NULL;
UserNode()
UserNode(User user)
this->user = user;
UserNode(User user, UserNode* next)
this->user = user;
this->next = next;
;
class UserList
public:
UserList()
size = 0;
isEmpty = true;
head = NULL;
;
UserList(const UserList& userList);
~UserList()
clearAll();
void add(User user)
if(head == NULL)
head = new UserNode();
head->user = user;
else
UserNode* temp = head;
while(temp->next != NULL)
temp = temp->next;
temp->next = new UserNode();
temp->next->user = user;
void clearAll()
while(head != NULL)
UserNode* temp = head;
head = head->next;
delete temp;
head = NULL;
User find(string username)
UserNode* temp = head;
while(temp != NULL)
if(temp->user.getUsername() == username)
return temp->user;
temp = temp->next;
User user;
return user;
bool contain(string username)
UserNode* temp = head;
while(temp != NULL)
if(temp->user.getUsername() == username)
return true;
temp = temp->next;
return false;
void display()
UserNode* temp = head;
while(temp != NULL)
cout << temp->user.getUsername() << "\t" << temp->user.getPassword() << "\t" << temp->user.getIsAdmin() << endl;
temp = temp->next;
void saveFile(string filename)
ofstream output;
output.open(filename, ios::out | ios::binary);
UserNode* temp = head;
while(temp != NULL)
User user = temp->user;
output.write(reinterpret_cast<char*>(&user.sz_user), sizeof(int));
output.write(user.getUsername(), user.sz_user * sizeof(char));
output.write(reinterpret_cast<char*>(&user.sz_pass), sizeof(int));
output.write(user.getPassword(), user.sz_pass * sizeof(char));
output.write(reinterpret_cast<char*>(&user.admin_state) , sizeof(int));
temp = temp->next;
output.close();
void loadFile(string filename)
clearAll();
ifstream input;
input.open(filename, ios::in | ios::binary);
User user;
while(input.read(reinterpret_cast<char*>(&user.sz_user), sizeof(int))) // read 1 user from file
char* usr = new char[user.sz_user];
input.read(usr, user.sz_user * sizeof(char));
user.setUsername(usr);
input.read(reinterpret_cast<char*>(&user.sz_pass), sizeof(int));
char* pass = new char[user.sz_pass];
input.read(pass, user.sz_pass * sizeof(char));
user.setPassword(pass);
int adm ;
input.read(reinterpret_cast<char*>(&adm), sizeof(int));
user.setAdmin(adm);
add(user);
input.close();
private:
int size;
bool isEmpty;
UserNode* head;
;
#endif
以及 User 类中的小改动。 (您可以将上面的序列化读写携带到这个类中,以制作更多样式的代码。)
#ifndef USER_H
#define USER_H
using namespace std;
#include <string.h>
#include <iostream>
class User
public:
User()
User(char* username, char* password, bool isAdmin)
this->username = username;
this->password = password;
this->isAdmin = isAdmin;
sz_user = strlen(username);
sz_pass = strlen(password);
admin_state = isAdmin ? 1: 0;
~User()
void setUsername(char* username)
this->username = username;
void setPassword(char* password)
this->password = password;
void setAdmin(int adm) isAdmin = adm ? true : false ;
char* getUsername()
return username;
char* getPassword()
return password;
bool getIsAdmin()
return isAdmin;
int sz_user;
int sz_pass;
int admin_state;
private:
char* username;
char* password;
bool isAdmin;
;
#endif
【讨论】:
以上是关于CPP 将类写入/读取到二进制文件中的主要内容,如果未能解决你的问题,请参考以下文章