如何读写非固定长度的结构到二进制文件c ++
how to read and write non-fixed-length structs to biniary file c++
我有结构向量:
typedef struct
{
uint64_t id = 0;
std::string name;
std::vector<uint64_t> data;
} entry;
我想写入文件:
FILE *testFile = nullptr;
testFile = fopen("test.b", "wb");
但是 read/write
的正常方法
fwrite(vector.data(), sizeof vector[0], vector.size(), testFile);
fread(vector.data(), sizeof(entry), numberOfEntries, testFile);
不起作用,因为条目的大小会根据
的内容而有很大差异
std::string name;
std::vector<uint64_t> data;
所以我想要有关如何处理 read/writing 数据 to/from 文件的方法和指示。
处理非固定大小的数据时,以某种方式跟踪大小很重要。您可以简单地指定固定大小元素的数量或整个结构的字节大小,并在读取结构时计算所需的值。我赞成第一个,尽管它有时会使调试变得有点困难。
这是一个如何制作灵活的序列化系统的例子。
struct my_data
{
int a;
char c;
std::vector<other_data> data;
}
template<class T>
void serialize(const T& v, std::vector<std::byte>& out)
{
static_assert(false, "Unsupported type");
}
template<class T>
requires std::is_trivially_copy_constructible_v<T>
void serialize(const T& v, std::vector<std::byte>& out)
{
out.resize(std::size(out) + sizeof(T));
std::memcpy(std::data(out) + std::size(out) - sizeof(T), std::bit_cast<std::byte*>(&v), sizeof(T));
}
template<class T>
void serialize<std::vector<T>>(const std::vector<T>& v, std::vector<std::byte>& out)
{
serialize<size_t>(std::size(v), out); // add size
for(const auto& e : v)
serialize<T>(v, out);
}
template<>
void serialize<my_data>(const my_data& v, std::vector<std::byte>& out)
{
serialize(v.a, out);
serialize(v.c, out);
serialize(v.data, out);
}
// And likewise you would do for deserialize
int main()
{
std::vector<std::byte> data;
my_data a;
serialize(a, data);
// write vector of bytes to file
}
这是一项繁琐的工作,并且已经有像 Google's Flatbuffers, Google's Protobuf or a single header BinaryLove3 这样的图书馆可以为您完成这项工作。其中一些与聚合类型开箱即用(意味着所有成员变量都是 public)。这是 BinaryLove3 的一个例子。
#include <iostream>
#include <vector>
#include <string>
#include <cstdint>
#include <string>
#include <list>
#include "BinaryLove3.hpp"
struct foo
{
uint32_t v0 = 3;
uint32_t v1 = 2;
float_t v2 = 2.5f;
char v3 = 'c';
struct
{
std::vector<int> vec_of_trivial = { 1, 2, 3 };
std::vector<std::string> vec_of_nontrivial = { "I am a Fox!", "In a big Box!" };
std::string str = "Foxes can fly!";
std::list<int> non_random_access_container = { 3, 4, 5 };
} non_trivial;
struct
{
uint32_t v0 = 1;
uint32_t v1 = 2;
} trivial;
};
auto main() -> int32_t
{
foo out = { 4, 5, 6.7f, 'd', {{5, 4, 3, 2}, {"cc", "dd"}, "Fly me to the moon..." , {7, 8, 9}}, {3, 4} };
auto data = BinaryLove3::serialize(bobux);
foo in;
BinaryLove3::deserialize(data, in);
return int32_t(0);
}
我有结构向量:
typedef struct
{
uint64_t id = 0;
std::string name;
std::vector<uint64_t> data;
} entry;
我想写入文件:
FILE *testFile = nullptr;
testFile = fopen("test.b", "wb");
但是 read/write
的正常方法fwrite(vector.data(), sizeof vector[0], vector.size(), testFile);
fread(vector.data(), sizeof(entry), numberOfEntries, testFile);
不起作用,因为条目的大小会根据
的内容而有很大差异std::string name;
std::vector<uint64_t> data;
所以我想要有关如何处理 read/writing 数据 to/from 文件的方法和指示。
处理非固定大小的数据时,以某种方式跟踪大小很重要。您可以简单地指定固定大小元素的数量或整个结构的字节大小,并在读取结构时计算所需的值。我赞成第一个,尽管它有时会使调试变得有点困难。
这是一个如何制作灵活的序列化系统的例子。
struct my_data
{
int a;
char c;
std::vector<other_data> data;
}
template<class T>
void serialize(const T& v, std::vector<std::byte>& out)
{
static_assert(false, "Unsupported type");
}
template<class T>
requires std::is_trivially_copy_constructible_v<T>
void serialize(const T& v, std::vector<std::byte>& out)
{
out.resize(std::size(out) + sizeof(T));
std::memcpy(std::data(out) + std::size(out) - sizeof(T), std::bit_cast<std::byte*>(&v), sizeof(T));
}
template<class T>
void serialize<std::vector<T>>(const std::vector<T>& v, std::vector<std::byte>& out)
{
serialize<size_t>(std::size(v), out); // add size
for(const auto& e : v)
serialize<T>(v, out);
}
template<>
void serialize<my_data>(const my_data& v, std::vector<std::byte>& out)
{
serialize(v.a, out);
serialize(v.c, out);
serialize(v.data, out);
}
// And likewise you would do for deserialize
int main()
{
std::vector<std::byte> data;
my_data a;
serialize(a, data);
// write vector of bytes to file
}
这是一项繁琐的工作,并且已经有像 Google's Flatbuffers, Google's Protobuf or a single header BinaryLove3 这样的图书馆可以为您完成这项工作。其中一些与聚合类型开箱即用(意味着所有成员变量都是 public)。这是 BinaryLove3 的一个例子。
#include <iostream>
#include <vector>
#include <string>
#include <cstdint>
#include <string>
#include <list>
#include "BinaryLove3.hpp"
struct foo
{
uint32_t v0 = 3;
uint32_t v1 = 2;
float_t v2 = 2.5f;
char v3 = 'c';
struct
{
std::vector<int> vec_of_trivial = { 1, 2, 3 };
std::vector<std::string> vec_of_nontrivial = { "I am a Fox!", "In a big Box!" };
std::string str = "Foxes can fly!";
std::list<int> non_random_access_container = { 3, 4, 5 };
} non_trivial;
struct
{
uint32_t v0 = 1;
uint32_t v1 = 2;
} trivial;
};
auto main() -> int32_t
{
foo out = { 4, 5, 6.7f, 'd', {{5, 4, 3, 2}, {"cc", "dd"}, "Fly me to the moon..." , {7, 8, 9}}, {3, 4} };
auto data = BinaryLove3::serialize(bobux);
foo in;
BinaryLove3::deserialize(data, in);
return int32_t(0);
}