You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++读写二进制文件时类内std::string对象读取为空问题求助

问题根源

你当前直接将类对象的原生内存整体写入二进制文件的操作,仅适用于POD(普通旧数据)类型的类。std::string不属于POD类型,它内部仅存储指向堆内存的指针、字符串长度、容量等元信息,实际的字符串内容存储在堆内存中。你写入文件的只是string对象本身的元数据,没有写入实际的字符串内容,读回时拿到的指针指向的是无效的堆内存地址,自然读不到数据,甚至可能触发程序崩溃。

修复方案

你需要手动实现类的序列化(对象转二进制数据写入文件)和反序列化(二进制数据读入重构对象)逻辑,不要直接读写整个对象的内存。

步骤1:给User类添加序列化/反序列化接口

修改类的public部分,新增两个方法:

class User{
private:
    unsigned int user_id;
    std::string user_name, home_address, e_mail;
    char gender, date_of_birth[11];
    unsigned long long int phone;
    bool has_car_booked, is_admin;

    void validate_data();
public:
    void get_data(bool);
    void display();
    // 新增序列化、反序列化方法
    void serialize(std::ofstream& ofs) const;
    void deserialize(std::ifstream& ifs);
};

步骤2:实现序列化逻辑

写文件时先写固定长度的POD成员,再处理string类型:先写入string的长度,再写入实际的字符串内容。

void User::serialize(std::ofstream& ofs) const {
    // 写入基础POD类型
    ofs.write(reinterpret_cast<const char*>(&user_id), sizeof(user_id));
    ofs.write(&gender, sizeof(gender));
    ofs.write(date_of_birth, sizeof(date_of_birth));
    ofs.write(reinterpret_cast<const char*>(&phone), sizeof(phone));
    ofs.write(reinterpret_cast<const char*>(&has_car_booked), sizeof(has_car_booked));
    ofs.write(reinterpret_cast<const char*>(&is_admin), sizeof(is_admin));

    // 处理std::string:先写长度,再写内容
    size_t len = user_name.size();
    ofs.write(reinterpret_cast<const char*>(&len), sizeof(len));
    ofs.write(user_name.data(), len);

    len = home_address.size();
    ofs.write(reinterpret_cast<const char*>(&len), sizeof(len));
    ofs.write(home_address.data(), len);

    len = e_mail.size();
    ofs.write(reinterpret_cast<const char*>(&len), sizeof(len));
    ofs.write(e_mail.data(), len);
}

步骤3:实现反序列化逻辑

读文件时和序列化顺序严格对应,读string时先读长度,再读取对应长度的内容赋值给string:

void User::deserialize(std::ifstream& ifs) {
    // 读取基础POD类型
    ifs.read(reinterpret_cast<char*>(&user_id), sizeof(user_id));
    ifs.read(&gender, sizeof(gender));
    ifs.read(date_of_birth, sizeof(date_of_birth));
    ifs.read(reinterpret_cast<char*>(&phone), sizeof(phone));
    ifs.read(reinterpret_cast<char*>(&has_car_booked), sizeof(has_car_booked));
    ifs.read(reinterpret_cast<char*>(&is_admin), sizeof(is_admin));

    // 处理std::string:先读长度,再读内容
    size_t len;
    ifs.read(reinterpret_cast<char*>(&len), sizeof(len));
    user_name.resize(len);
    ifs.read(user_name.data(), len);

    ifs.read(reinterpret_cast<char*>(&len), sizeof(len));
    home_address.resize(len);
    ifs.read(home_address.data(), len);

    ifs.read(reinterpret_cast<char*>(&len), sizeof(len));
    e_mail.resize(len);
    ifs.read(e_mail.data(), len);
}

步骤4:修改读写文件的函数

不要直接读写整个对象内存,改为调用上面实现的序列化/反序列化方法:

void read_from_file(const std::string &filename){
    std::ifstream file;
    file.open(filename, std::ios::binary | std::ios::in);
    if(!file){
        std::cout<<"Read File does not exist\n";
        return;
    }

    User tempobj;
    tempobj.deserialize(file); // 调用反序列化方法
    tempobj.display();
    file.close();   
}

void write_to_file(const User &obj, const std::string &filename){
    std::ofstream file;
    file.open(filename, std::ios::binary | std::ios::out);
    obj.serialize(file); // 调用序列化方法
    file.close();
}

注意事项

  • 序列化和反序列化的字段顺序必须严格一致,否则会出现数据读错的问题
  • 如果需要跨平台运行,还要额外处理大小端、不同平台基础类型长度差异、结构体字节对齐的问题,本地使用的话上述代码已经可以满足需求。

内容的提问来源于stack exchange,提问作者Dev Narula

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 05:54:04