无法将类对象数组写入/读取到文件

Can't write/read an array of class objects to a file

本文关键字:读取 文件 数组 对象      更新时间:2023-10-16

>我有一个具有 3 个参数的类用户:id、pass、active

我想将用户对象数组写入文件,但它不起作用。

有时它是工作,但之后我只能读取这些参数:id,活动。

参数传递给了我:什么都没有,一些字符或一个字符(几乎是"a"(。

班级:

class User {
int id;
char *pass;
bool active;
public:
User() {
id = -1;
pass = NULL;
active = 0;
}
User(int id, char * pass, bool active = 1) {
this->id = id;
if (pass) delete[] pass;
this->pass = new char[strlen(pass)];
memcpy(this->pass, pass, strlen(this->pass));
this->active = active;
}
void set_id(int id) {
this->id = id;
}
void set_active(bool active) {
this->active = active;
}
void set_pass(char *pass) {
this->pass = new char[strlen(pass)];
memcpy(this->pass, pass, strlen(this->pass));
}
int get_id() {
return id;
}
char *get_pass() {
return pass;
}
bool get_active() {
return active;
}
};

这是我的数组:

User *users = new User[999999]; int size_ = 0;

主要:

int main() {
fstream r_user("user.txt", ios::binary | ios::in);
if (!r_user) {
r_user.close();
char pass[100];
cerr << "You don't have any user, please create user" << endl;
cout << "User pass: "; cin >> pass;
users[0].set_id(0);
users[0].set_pass(pass);
users[0].set_active(1);
size_++;
cout << users[0].get_pass();
fstream w_user("user.txt", ios::binary | ios::out);
w_user.write(reinterpret_cast<char *>(users), size_ * sizeof(User));
w_user.close();
}
else {
r_user.seekg(0, r_user.end);
size_ = r_user.tellg();
r_user.seekg(0, r_user.beg);
size_ = size_ / sizeof(users);
r_user.read(reinterpret_cast<char *>(users),  99999 * sizeof(User));
r_user.close();
cout << users[0].get_pass();
}
return 0;
}

该文件不为空。

您的代码在处理传递存储的方式中遇到了两个严重错误。

您使用:

this->pass = new char[strlen(pass)];
memcpy(this->pass, pass, strlen(this->pass));

请注意,任何字符串都以 NULL 字节结尾,因此要复制的数据大小为 strlen(pass(+1。例如:strlen("abcedf"( == 6,但你需要 7 个字节来存储它。

后果可能是戏剧性的:当尝试读取字符串时,软件将命中连接到该区域的其他内存块,并将读取错误的字符串(因为没有 NULL 字节停止字符串读取(。随着时间的流逝,随着函数的增加,这个小错误可能会将内存泄漏到文件中,可能导致崩溃或以逐个关闭的方式写入 NULL 字节,函数停止正常工作,一切都会走下坡路......听起来像地狱吧?

this->pass = new char[strlen(pass) + 1];
memcpy(this->pass, pass, strlen(this->pass) + 1);

或者,更优雅:

this->pass = new char[strlen(pass) + 1];
this->pass = strcpy(this->pass, pass);

或者更优雅、更安全:

this->pass = strdup(pass);

您可能还希望使用独特的私有函数进行此类管理,实际上此敏感部分在您的代码中是重复的。

也许是哈希通行证?:-(如果你想要一些严肃的工作,那就去Bcrypt:https://github.com/rg3/bcrypt

我还看到你为传递的东西使用指针。因此,您可以保存指针,但不保存指向的数据。

加载指针的值时,内存中没有任何内容,或者如果有东西,那肯定不是您的传递(从未保存过(。您必须使用静态缓冲区来存储该传递,并确保类将保持 POD(纯旧数据(。

使用散列密码时,最终缓冲区将具有确定性大小。例如:

char bcrypt_password[64];

而不是:

char *pass;

但要注意你的分配:

new User[999999];

会消耗相当多的内存。

我会是你,我会去序列化你的对象,以及 import(( export(( 方法的集成。基本的 CSV 序列化将允许以后的数据库导入/导出。

fstream只转储原始数据,因此它仅适用于常规变量。

passchar*的,所以它存储的是指针地址而不是字符串值。

您需要为类自定义序列化。 将方法添加到 User 类中以Load()Save(),以便可以处理pass变量。他们应该接受fstream缓冲区,以便他们可以读/写它。