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

时间:2017-07-04 22:22:45

标签: c++ file fstream

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

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

有时它是有效的,但之后我只能读取这些参数:id,active。

参数传递给了我:没有,一些字符或一个字符(几乎' 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;
}

该文件不为空。

2 个答案:

答案 0 :(得分:0)

您的代码在处理通行证存储方式方面遇到两个严重错误。

您使用:

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

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

后果可能是戏剧性的:当尝试读取字符串时,软件将触及连接到该区域的其他内存块,并将读取错误的字符串(因为没有NULL字节会停止字符串读取)。随着时间的推移,有了更多的功能,这个小错误可能会将内存泄漏到文件中,可能会导致崩溃或以一种一种方式写入NULL字节,功能会停止正常工作而且一切都在下坡......听起来好像呃? / p>

    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序列化将允许以后的DB导入/导出。

答案 1 :(得分:0)

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

passchar*,因此存储指针地址而不是字符串值。

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