导读:本期聚焦于小伙伴创作的《c++怎么将结构体存入二进制文件_序列化与反序列化【详解】》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《c++怎么将结构体存入二进制文件_序列化与反序列化【详解】》有用,将其分享出去将是对创作者最好的鼓励。

在C++开发中,经常需要将结构体数据持久化存储到文件中,二进制文件相比文本文件占用空间更小、读写速度更快,因此将结构体序列化后存入二进制文件是常用的方案。序列化就是把结构体的数据按照特定格式转换为可存储的字节流,反序列化则是从字节流中还原出原来的结构体数据。

c++怎么将结构体存入二进制文件_序列化与反序列化【详解】

基础序列化与反序列化实现

对于不包含指针成员、没有虚函数的简单结构体,可以直接通过二进制读写的方式实现序列化与反序列化,核心是使用ofstreamifstream的write和read方法。

简单结构体示例

首先定义一个不包含指针的基础结构体:

#include <iostream>
#include <fstream>
#include <cstring>

// 定义简单结构体
struct Student {
    int id;
    char name[20];
    float score;
};

int main() {
    // 原始数据
    Student stu1;
    stu1.id = 1001;
    strcpy(stu1.name, "张三");
    stu1.score = 92.5f;

    // 序列化:写入二进制文件
    std::ofstream outFile("student.dat", std::ios::binary);
    if (!outFile) {
        std::cout << "文件打开失败" << std::endl;
        return 1;
    }
    // 直接写入整个结构体
    outFile.write(reinterpret_cast<const char*>(&stu1), sizeof(Student));
    outFile.close();

    // 反序列化:从二进制文件读取
    Student stu2;
    std::ifstream inFile("student.dat", std::ios::binary);
    if (!inFile) {
        std::cout << "文件打开失败" << std::endl;
        return 1;
    }
    inFile.read(reinterpret_cast<char*>(&stu2), sizeof(Student));
    inFile.close();

    // 输出还原后的数据
    std::cout << "id: " << stu2.id << std::endl;
    std::cout << "name: " << stu2.name << std::endl;
    std::cout << "score: " << stu2.score << std::endl;
    return 0;
}

注意事项

  • 这种方式只适用于POD(Plain Old Data)类型结构体,即没有用户定义的构造函数、析构函数、虚函数,成员也没有指针或动态分配的内存。
  • 不同平台的内存对齐规则可能不同,直接写入的结构体字节大小可能存在差异,跨平台使用时需要手动处理对齐问题,或者逐个成员读写。

包含动态成员的结构体处理

如果结构体中包含指针、动态数组等成员,直接写入结构体只会保存指针的地址,而不是指向的实际数据,反序列化后指针会指向无效内存,因此需要手动逐个成员序列化。

带动态成员的结构体示例

#include <iostream>
#include <fstream>
#include <cstring>

struct Person {
    int age;
    char* name; // 动态分配的姓名
    int nameLen; // 姓名长度,用于反序列化时分配内存
};

// 序列化函数
void serializePerson(const Person& p, const char* fileName) {
    std::ofstream outFile(fileName, std::ios::binary);
    if (!outFile) {
        std::cout << "文件打开失败" << std::endl;
        return;
    }
    // 先写入age
    outFile.write(reinterpret_cast<const char*>(&p.age), sizeof(int));
    // 写入姓名长度
    outFile.write(reinterpret_cast<const char*>(&p.nameLen), sizeof(int));
    // 写入姓名实际内容
    outFile.write(p.name, p.nameLen);
    outFile.close();
}

// 反序列化函数
Person deserializePerson(const char* fileName) {
    Person p;
    std::ifstream inFile(fileName, std::ios::binary);
    if (!inFile) {
        std::cout << "文件打开失败" << std::endl;
        p.age = 0;
        p.name = nullptr;
        p.nameLen = 0;
        return p;
    }
    // 读取age
    inFile.read(reinterpret_cast<char*>(&p.age), sizeof(int));
    // 读取姓名长度
    inFile.read(reinterpret_cast<char*>(&p.nameLen), sizeof(int));
    // 分配内存
    p.name = new char[p.nameLen + 1];
    // 读取姓名内容
    inFile.read(p.name, p.nameLen);
    p.name[p.nameLen] = ''; // 添加字符串结束符
    inFile.close();
    return p;
}

int main() {
    // 构造原始数据
    Person p1;
    p1.age = 25;
    const char* rawName = "李四";
    p1.nameLen = strlen(rawName);
    p1.name = new char[p1.nameLen + 1];
    strcpy(p1.name, rawName);

    // 序列化
    serializePerson(p1, "person.dat");

    // 反序列化
    Person p2 = deserializePerson("person.dat");

    // 输出结果
    std::cout << "age: " << p2.age << std::endl;
    std::cout << "name: " << p2.name << std::endl;

    // 释放内存
    delete[] p1.name;
    delete[] p2.name;
    return 0;
}

常见问题与解决方案

问题解决方案
跨平台读写数据不一致统一使用小端或大端字节序,读写时做字节序转换,避免直接依赖平台默认对齐
结构体版本升级后旧数据无法读取在序列化数据开头添加版本号字段,反序列化时根据版本号做兼容处理
动态成员内存泄漏反序列化分配的内存需要在使用完成后手动释放,或者改用智能指针管理

总结

C++中实现结构体二进制文件的序列化与反序列化,核心是根据结构体的成员类型选择合适的读写方式。简单POD结构体可以直接整体读写,包含动态成员的结构体需要逐个成员处理。实际开发中还需要考虑跨平台、版本兼容、内存管理等问题,才能保证数据存储和读取的稳定性。

C++结构体二进制文件序列化反序列化修改时间:2026-07-16 01:21:13

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。