C++ 如何在二进制文件中读取/写入结构?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5506645/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to read / write a struct in Binary Files?
提问by Shankar Raju
I am facing a small problem. I have a struct, which has a vector. Note that the vector is dynamic per every iteration. Now, in a particular iteration, how do I store the struct which contains a vector of size n to a binary file?
我正面临一个小问题。我有一个结构体,它有一个向量。请注意,每次迭代的向量都是动态的。现在,在特定的迭代中,如何将包含大小为 n 的向量的结构存储到二进制文件中?
Also, when retrieving, assume that I know how the size of the vector, how to I retrieve from the binary file, the struct variable containing the vector of all the stored elements?
另外,在检索时,假设我知道向量的大小,如何从二进制文件中检索包含所有存储元素的向量的结构变量?
I am able to store something to the binary file (as I can see the size increasing when writing), but when I am trying to retrieve back the elements, I am getting size of vector to be zero.
我能够将一些内容存储到二进制文件中(因为我可以看到写入时大小增加),但是当我尝试检索元素时,我将向量的大小设置为零。
Unfortunately, I have to achieve this using the standard STL and not use any third-party libraries.
不幸的是,我必须使用标准 STL 来实现这一点,而不是使用任何第三方库。
回答by karlphillip
You should have a look at Boost Serialization.
你应该看看Boost Serialization。
If you can't use 3rd party libraries, you must know that C++ doesn't support serialization directly. This means you'll have to do it yourself.
如果你不能使用 3rd 方库,你必须知道 C++ 不直接支持序列化。这意味着你必须自己做。
This articleshows a nice way of serializing a custom object to the disk and retrieving it back. And this tutorialshows you how to get started right now with fstream.
本文展示了一种将自定义对象序列化到磁盘并取回它的好方法。而本教程向您展示如何让现在开始fstream的。
This is my attempt:
这是我的尝试:
EDIT: since the OP asked how to store/retrieve more than record I decided to updated the original code.
编辑:由于 OP 询问如何存储/检索比记录更多的内容,因此我决定更新原始代码。
So, what changed? Now there's an arraystudent_t apprentice[3];
to store information of 3 students. The entire array is serialized to the disk and then it's all loaded back to the RAM where reading/searching for specific records is possible. Note that this is a very very small file (84 bytes). I do not suggest this approach when searching records on huge files.
那么,发生了什么变化?现在有一个数组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;
}
Outputs:
输出:
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
Dump of the binary file:
转储二进制文件:
$ hexdump -c students.data
0000000 j o h n 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;
}
237 { ##代码## ? ? { ? 025 ##代码## ##代码## ##代码##
0000010 ( ? ? \b 4 ? ? \b 8 ? ? \b j e r r
0000020 y ##代码## ? ##代码## ? ? | ##代码## 026 ##代码## ##代码## ##代码## @ ? ? \b
0000030 L ? ? \b P ? ? \b j i m m y ##代码## ##代码## ##代码##
0000040 ? 6 ? ##代码## 027 ##代码## ##代码## ##代码## X ? ? \b d ? ? \b
0000050 h ? ? \b
0000054
回答by Jerry Coffin
You typically serialize a vector by writing the length of the vector, followed by that number of elements. When you read it back in, having the length come first lets you know how many more items to read as part of that vector. As a simple first approximation, consider something like this:
您通常通过写入向量的长度,然后是该元素数来序列化向量。当您读回它时,首先将长度放在首位让您知道作为该向量的一部分要读取多少项。作为一个简单的第一次近似,考虑这样的事情:
##代码##This is open to lots of tweaks, improvements, and simple modifications -- just for example, for the moment, I've passed the vector (or whatever -- could be a std::deque, etc.) by reference rather than passing iterators. That probably simplifies most use, but doesn't fit as well with the rest of the library.
这对许多调整、改进和简单的修改都是开放的——例如,目前,我已经通过引用传递了向量(或其他任何东西——可能是 std::deque 等)而不是传递迭代器。这可能简化了大多数使用,但不太适合库的其余部分。
This also serializes in text format, one number per line. Discussions comparing text to binary have happened before, so I won't try to repeat all the arguments here -- I'll just note that the same basic idea can be done in binary format just as well as text.
这也以文本格式序列化,每行一个数字。之前已经讨论过将文本与二进制进行比较,因此我不会尝试在此处重复所有论点——我只是要指出,同样的基本思想可以以二进制格式和文本格式完成。