无法在二进制文件中存储动态数组

Unable to store dynamic arrays in binary files

本文关键字:存储 动态 数组 二进制文件      更新时间:2023-10-16

我需要能够在结构中存储数组,然后将结构另存为字节文件。问题是我要求数组是动态的。指针数组是不可能的,因为在保存时,它只会保存指针,而矢量将不起作用。这是我正在使用的当前设置的示例。

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使用类型来确定大小,而不是任何运行时值。所以你可能会使用mallocfree,这在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);
}