在 C++ 中,可以将复杂的结构体保存到二进制文件中,并从二进制文件中读取它。为了实现这一点,你可以使用文件流库 。以下是一个示例,展示如何将一个复杂的结构体保存到二进制文件中,并从二进制文件中读取它。

1. 示例结构体

假设我们有一个复杂的结构体 Person,其中包含一些基本数据类型和字符串。

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstring>
 
struct Person {
    char name[50];
    int age;
    double height;
    std::vector<int> scores;
 
    // Method to serialize the structure to a binary stream
    void serialize(std::ofstream& ofs) const {
        ofs.write(name, sizeof(name));
        ofs.write(reinterpret_cast<const char*>(&age), sizeof(age));
        ofs.write(reinterpret_cast<const char*>(&height), sizeof(height));
 
        size_t scores_size = scores.size();
        ofs.write(reinterpret_cast<const char*>(&scores_size), sizeof(scores_size));
        ofs.write(reinterpret_cast<const char*>(scores.data()), scores.size() * sizeof(int));
    }
 
    // Method to deserialize the structure from a binary stream
    void deserialize(std::ifstream& ifs) {
        ifs.read(name, sizeof(name));
        ifs.read(reinterpret_cast<char*>(&age), sizeof(age));
        ifs.read(reinterpret_cast<char*>(&height), sizeof(height));
 
        size_t scores_size;
        ifs.read(reinterpret_cast<char*>(&scores_size), sizeof(scores_size));
        scores.resize(scores_size);
        ifs.read(reinterpret_cast<char*>(scores.data()), scores_size * sizeof(int));
    }
};

保存结构体到二进制文件

void savePersonToFile(const Person& person, const std::string& filename) {
    std::ofstream ofs(filename, std::ios::binary);
    if (!ofs) {
        std::cerr << "Error opening file for writing: " << filename << std::endl;
        return;
    }
    person.serialize(ofs);
    ofs.close();
}

从二进制文件读取结构体

Person loadPersonFromFile(const std::string& filename) {
    Person person;
    std::ifstream ifs(filename, std::ios::binary);
    if (!ifs) {
        std::cerr << "Error opening file for reading: " << filename << std::endl;
        return person;
    }
    person.deserialize(ifs);
    ifs.close();
    return person;
}

示例用法

int main() {
    Person person;
    std::strcpy(person.name, "John Doe");
    person.age = 30;
    person.height = 5.9;
    person.scores = {85, 90, 78};
 
    std::string filename = "person.dat";
 
    // Save to binary file
    savePersonToFile(person, filename);
 
    // Load from binary file
    Person loaded_person = loadPersonFromFile(filename);
 
    // Display loaded person information
    std::cout << "Name: " << loaded_person.name << std::endl;
    std::cout << "Age: " << loaded_person.age << std::endl;
    std::cout << "Height: " << loaded_person.height << std::endl;
    std::cout << "Scores: ";
    for (int score : loaded_person.scores) {
        std::cout << score << " ";
    }
    std::cout << std::endl;
 
    return 0;
}

解释

1.序列化和反序列化方法:

  1. serialize 方法将结构体的各个成员写入到二进制文件中。
  2. deserialize 方法从二进制文件中读取结构体的各个成员。
    2.文件流:

  3. 使用 std::ofstream 打开文件进行写操作,并设置为二进制模式(std::ios::binary)。

  4. 使用 std::ifstream 打开文件进行读操作,并设置为二进制模式(std::ios::binary)。

3.字符串和动态数组的处理:

  1. std::vector 的大小和数据都需要序列化和反序列化,因为它是一个动态数组。
  2. char[] 字符数组可以直接写入和读取。
    通过上述方法,你可以将复杂的结构体保存到二进制文件中,并从二进制文件中读取它。这种方法可以确保结构体的数据被正确保存和恢复。

2. 运行结果

3. 其它实例

使用c语言的形式,混合的写入 char[], int, 自定义结构体

#include <stdio.h>
#include <memory>
#include <iostream>
#include <cstring>
#include <algorithm>
 
// 定义结构体
typedef struct {
    float a;
    float b;
    float c;
    int x;
    int y;
    char f1[3];
    char f2[3];
    char f3[3];
} MyStruct;
 
 
int main() {
    const char *filename = "data_john2.bin";
    FILE *file;
 
    // 打开文件以写入二进制数据
    file = fopen(filename, "wb");
    if (file == NULL) {
        perror("Error opening file for writing");
        return 1;
    }
 
    char verbbon[8] = "v1.0";
    int level = 1;
    
    fwrite (&verbbon , sizeof(char), sizeof(verbbon), file);
    
    fwrite (&level , sizeof(int), 1, file);
    
    MyStruct data;
    data.a = 1.1;
    data.b = 1.2;
    data.c = 1.3;
    data.x = 10;
    data.y = 92;
 
    
     memset(data.f1,0,sizeof(data.f1));
     memset(data.f2,0,sizeof(data.f2));
     memset(data.f3,0,sizeof(data.f3));
    //data.f1 = "aa";
     std::string aa_str = "aa";
    strncpy(data.f1, "aa", sizeof("aa")); // 注意:sizeof("aa") == 3
    strncpy(data.f2, "bb", 2);
    strncpy(data.f3,"cc", 2);
   /* 
    std::string aa_str = "aa"; 
    std::copy_n(aa_str.begin(), aa_str.size(), data.f1);  
    data.f1[aa_str.size()] = '\0';
 
    std::string bb_str = "bb"; 
    std::copy_n(bb_str.begin(), aa_str.size(), data.f2);  
    data.f2[bb_str.size()] = '\0';
    
    std::string cc_str = "cc"; 
    std::copy_n(cc_str.begin(), cc_str.size(), data.f3);  
    data.f3[cc_str.size()] = '\0';
   */
   
  
    char data2[100];
    memset(data2,0,sizeof(data2));
    
    std::string info = "hello world";
    strncpy(data2,info.c_str(), info.size());
      
    fwrite(reinterpret_cast<char *>(&data), sizeof(MyStruct), 1, file);
    
    fwrite (&data2 , sizeof(char), sizeof(data2), file);
    // 关闭文件
    fclose(file);
    printf("Data saved successfully.\n");
 
    
    
    
    
    // ===========================================
    // 打开文件以读取二进制数据
    file = fopen(filename, "rb");
    if (file == NULL) {
        perror("Error opening file for reading");
        return 1;
    }
    
     char r_version[8];
     int r_level;
     // 为读取的数据分配内存
     MyStruct *readData =reinterpret_cast<MyStruct*> (malloc(1 * sizeof(MyStruct)));
     
     //MyStruct *readData1 =reinterpret_cast<MyStruct*> (malloc(1 * sizeof(MyStruct)));
     
    
     fread(&r_version, sizeof(char), sizeof(r_version), file);
     fread(&r_level, sizeof(int), 1, file);
    
     
     
   //size_t read = fread(data, sizeof(MyStruct), count, file);
    size_t read = fread(reinterpret_cast<char *>(readData), sizeof(MyStruct), 1, file);
    if (read != 1) {
        perror("Error reading from file");
    }
   
   char r_data2[100];
   memset(r_data2,0,sizeof(r_data2));
   read = fread(&r_data2, sizeof(char), sizeof(r_data2), file);
    
    
    std::cout << "r_version:" << r_version << std::endl;
    std::cout << "r_level:" << r_level << std::endl;
    std::cout << "readData:" << readData->a << ", " 
		    << readData->a << ", " 
		    << readData->b << ", " 
		    << readData->c << ", " 
		    << readData->x << ", " 
		    << readData->y << ", " 
		    << readData->f1 << ", " 
		    << readData->f2 << ", " 
		    << readData->f3 << ", " 
		    << std::endl;
	
    std::cout << "r_data2:" << r_data2 << ", "    << std::endl;
 
    
    // 关闭文件
    fclose(file);
    return 0;
}

运行结果