如何读取/写入二进制文件中的结构?

Sha*_*aju 21 c++ struct binaryfiles vector

我正面临一个小问题.我有一个结构,它有一个向量.请注意,向量在每次迭代时都是动态的.现在,在特定的迭代中,如何将包含大小为n的向量的结构存储到二进制文件中?

另外,在检索时,假设我知道向量的大小,如何从二进制文件中检索,包含所有存储元素的向量的struct变量?

我可以将内容存储到二进制文件中(因为我可以看到写入时大小增加),但是当我尝试检索元素时,我将向量的大小设置为零.

不幸的是,我必须使用标准STL来实现这一点,而不是使用任何第三方库.

kar*_*lip 28

你应该看看Boost Serialization.

如果您不能使用第三方库,则必须知道C++不直接支持序列化.这意味着你必须自己做.

本文介绍了一种将自定义对象序列化到磁盘并将其检索回来的好方法.而本教程将向您展示如何立即开始使用fstream的.

这是我的尝试:

编辑:由于OP询问如何存储/检索多于记录我决定更新原始代码.

那么,改变了什么?现在有一个数组 student_t apprentice[3];来存储3名学生的信息.整个阵列被序列化到磁盘,然后全部加载回RAM,在那里可以读取/搜索特定记录.请注意,这是一个非常小的文件(84字节).在巨大文件上搜索记录时,我不建议这种方法.

#include <fstream>
#include <iostream>
#include <vector>
#include <string.h>

using namespace std;


typedef struct student
{
    char name[10];
    int age;
    vector<int> grades;
}student_t;

int main()
{
    student_t apprentice[3];  
    strcpy(apprentice[0].name, "john");
    apprentice[0].age = 21;
    apprentice[0].grades.push_back(1);
    apprentice[0].grades.push_back(3);
    apprentice[0].grades.push_back(5);    

    strcpy(apprentice[1].name, "jerry");
    apprentice[1].age = 22;
    apprentice[1].grades.push_back(2);
    apprentice[1].grades.push_back(4);
    apprentice[1].grades.push_back(6);

    strcpy(apprentice[2].name, "jimmy");
    apprentice[2].age = 23;
    apprentice[2].grades.push_back(8);
    apprentice[2].grades.push_back(9);
    apprentice[2].grades.push_back(10);

    // Serializing struct to student.data
    ofstream output_file("students.data", ios::binary);
    output_file.write((char*)&apprentice, sizeof(apprentice));
    output_file.close();

    // Reading from it
    ifstream input_file("students.data", ios::binary);
    student_t master[3];
    input_file.read((char*)&master, sizeof(master));         

    for (size_t idx = 0; idx < 3; idx++)
    {
        // If you wanted to search for specific records, 
        // you should do it here! if (idx == 2) ...

        cout << "Record #" << idx << endl;
        cout << "Name: " << master[idx].name << endl;
        cout << "Age: " << master[idx].age << endl;
        cout << "Grades: " << endl;
        for (size_t i = 0; i < master[idx].grades.size(); i++)
           cout << master[idx].grades[i] << " ";
        cout << endl << endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

产出:

Record #0
Name: john
Age: 21
Grades: 
1 3 5 

Record #1
Name: jerry
Age: 22
Grades: 
2 4 6 

Record #2
Name: jimmy
Age: 23
Grades: 
8 9 10
Run Code Online (Sandbox Code Playgroud)

转储二进制文件:

$ hexdump -c students.data 
0000000   j   o   h   n  \0 237   {  \0   ?   ?   {   ? 025  \0  \0  \0
0000010   (   ?   ?  \b   4   ?   ?  \b   8   ?   ?  \b   j   e   r   r
0000020   y  \0   ?  \0   ?   ?   |  \0 026  \0  \0  \0   @   ?   ?  \b
0000030   L   ?   ?  \b   P   ?   ?  \b   j   i   m   m   y  \0  \0  \0
0000040   ?   6   ?  \0 027  \0  \0  \0   X   ?   ?  \b   d   ?   ?  \b
0000050   h   ?   ?  \b                                                
0000054
Run Code Online (Sandbox Code Playgroud)

  • 你通常没有任何机会对std :: vector <>进行struct dump.[我想它_might_适用于某些实现的(非常)小向量!] (5认同)
  • 这段代码非常糟糕.它似乎只在你的测试中工作,因为你正在将数据读回到写入它的同一个进程中,所以从磁盘读取的指针仍然指向相同的对象.对象数据从未正确保存,并且当原始对象被销毁时(可能通过进程重新启动),从文件读回的数组将停止工作. (5认同)
  • 为什么这个答案有-3? (2认同)
  • @stackoverflowwww:`vector`确实是问题,它包含容量,计数和指向真实数据的指针.将指针保存到磁盘是没有意义的,您希望保存它指向的数据.杰里的回答解释了这样做的好方法. (2认同)
  • 被否决了,因为以这种方式“序列化”`std::vector` 完全是无稽之谈。 (2认同)

Jer*_*fin 16

您通常通过写入向量的长度来序列化向量,然后是该元素的数量.当你重新阅读它时,首先让长度让你知道还有多少项要作为该向量的一部分阅读.作为一个简单的第一近似,考虑这样的事情:

template<class T>
std::ostream &operator<<(std::ostream &output, T const &input) {
    T::size_type size = input.size();

    output << size << "\n";
    std::copy(input.begin(), input.end(), 
         std::ostream_iterator<T::value_type>(output, "\n"));

    return output;
}

template<class T>
std::istream &operator>>(std::istream &input, T &output) {
    T::size_type size, i;

    input >> size;
    output.resize(size);
    std::copy_n(
        std::istream_iterator<t::value_type>(input),
        size,
        output.begin());

    return input;
}
Run Code Online (Sandbox Code Playgroud)

这可以通过大量的调整,改进和简单的修改 - 例如,目前,我通过引用传递了向量(或者其他任何东西 - 可能是std :: deque等)而不是传递迭代器.这可能简化了大多数用途,但不适合库的其余部分.

这也以文本格式序列化,每行一个数字.前面已经讨论过将文本与二进制相比较的讨论,所以我不会在这里重复所有的论点 - 我只会注意到同样的基本思想可以用二进制格式和文本一样完成.