无法在二进制文件中存储动态数组
问题描述:
我需要能够将数组存储在结构中,然后将结构保存为字节文件。问题是我需要数组是动态的。指针数组不存在,因为当涉及到保存时,只保存指针并且矢量不起作用。这是我正在使用的当前设置的一个示例。无法在二进制文件中存储动态数组
struct GenerationBase
{
//float value[]; // Will override data currently in ram
//float value[10]; // Dose not work as it needs to have a dynamic size
//float* value; // Will only save the pointer value
//std::vector<float> value; // Dose not work for some reason
};
template<typename T>
void write_to_file(std::ofstream& stream, T data)
{
stream.write(reinterpret_cast<const char*>(&data), sizeof(T));
}
int main()
{
const char* file = "file.txt";
GenerationBase write{};
std::ofstream stream_write(file, std::ios::binary);
write_to_file(stream_write, write);
stream_write.close();
}
答
评论中的所有注释都是正确的 - 您必须使用一些库进行序列化。 protobuf,boost :: serialization是很好的二进制格式,JSON和XML是文本存储的不错选择。
这种方法存在更多的基本问题,但是你的结构的字节组成依赖于很多东西:编译器,字节序,32位或64位体系结构。这意味着您不能简单地将C++数据结构的字节内容存储在文件中。
答
当从“运行时而不是编译时确定大小”的意义上使用动态大小的结构时,可以使用一个未指定大小的数组,如float value[]
作为该结构的最后一个成员。但是请注意,您必须“手动”为结构分配适当大小的内存。 C就是这种情况,C++也是如此。不幸的是,使用运算符new
时手动定义大小非常棘手,因为new
使用该类型来确定大小,而不是任何运行时值。所以你可能会使用malloc
和free
,这在C++中看起来不太合适。
更简单的解决方案是使用std::vector
,而不是写入结构存储器的转储,而是写入向量的内容。
无论如何,对于您遵循的每种方法,您还必须将数组中元素的数量写入文件;否则 - 至少如果您将几个这样的结构体顺序写入同一个文件中 - 您可能会丢失信息,该文件中存储的(动态)数组实际具有多少个元素。那么当然,读入过程必须考虑这个数字并相应地创建/修改structs
。
请参阅以下代码,它演示了(1)向量方法和(2)具有可变大小方法的结构。希望它以某种方式帮助。
struct GenerationBase_UsingVector
{
std::vector<float> value;
void write(std::ofstream &w) const {
size_t num_elems = value.size();
w.write((const char*)&num_elems, sizeof(num_elems));
w.write((const char*)value.data(), num_elems*sizeof(float));
}
void read(std::ifstream &r) {
size_t num_elems;
r.read((char *)&num_elems, sizeof(num_elems));
float f;
while (num_elems--) {
r.read((char *)&f, sizeof(f));
value.push_back(f);
}
}
};
struct GenerationBase_PlainArray
{
size_t num_elems;
float value[];
static GenerationBase_PlainArray* create(size_t num_elems)
{
GenerationBase_PlainArray* result = (GenerationBase_PlainArray*)malloc(sizeof(GenerationBase_PlainArray) + num_elems*sizeof(float));
result->num_elems = num_elems;
return result;
}
static struct GenerationBase_PlainArray* newFromStream(std::ifstream &r) {
size_t num_elems;
r.read((char *)&num_elems, sizeof(num_elems));
GenerationBase_PlainArray* result = GenerationBase_PlainArray::create(num_elems);
r.read((char *)result->value, num_elems*sizeof(float));
return result;
}
void write(std::ofstream &w) const {
w.write((const char*)&num_elems, sizeof(num_elems));
w.write((const char*)value, num_elems*sizeof(float));
}
};
int main() {
GenerationBase_UsingVector gb_vector_forwrite;
gb_vector_forwrite.value.push_back(1.0);
gb_vector_forwrite.value.push_back(2.0);
gb_vector_forwrite.value.push_back(3.0);
gb_vector_forwrite.value.push_back(4.0);
gb_vector_forwrite.value.push_back(5.0);
gb_vector_forwrite.value.push_back(6.0);
std::ofstream write("test.bin", std::ios::binary);
gb_vector_forwrite.write(write);
write.close();
GenerationBase_UsingVector gb_vector_forread;
std::ifstream read("test.bin", std::ios::binary);
gb_vector_forread.read(read);
read.close();
for (auto f : gb_vector_forread.value) {
cout << f << endl;
}
GenerationBase_PlainArray* gb_array_forwrite = GenerationBase_PlainArray::create(6);
gb_array_forwrite->value[0] = 1.0;
gb_array_forwrite->value[1] = 2.0;
gb_array_forwrite->value[2] = 3.0;
gb_array_forwrite->value[3] = 4.0;
gb_array_forwrite->value[4] = 5.0;
gb_array_forwrite->value[5] = 6.0;
std::ofstream write2("test2.bin", std::ios::binary);
gb_array_forwrite->write(write2);
write2.close();
free(gb_array_forwrite);
std::ifstream read2("test2.bin", std::ios::binary);
GenerationBase_PlainArray *gb_array_forread = GenerationBase_PlainArray::newFromStream(read2);
read2.close();
for (int i=0; i<gb_array_forread->num_elems; i++) {
cout << gb_array_forread->value[i] << endl;
}
free(gb_array_forread);
}
建议使用'德/ Serialiazation'.http://www.boost.org/doc/libs/1_36_0/libs/serialization/doc/index.html – Raindrop7
的sizeof(T)是一个编译时的事情 - 如果你的数组是动态的,它不是一个选项 – WindyFields
一个'vector'比简单的数据阵列更复杂。你不能只拿它的地址。 – AndyG