如何在 C++ 中序列化/反序列化 INT
How to serialize / deserialize INTs in C++
所以,我想在 C++ 中为一些 int 变量实现简单的序列化,但我真的不知道如何...
我的目标如下:
我基本上希望能够将任何整数转换为二进制,最好是通过简单的函数调用。
// Here´s some dummy code of what I essentially want to do
int TestVariable = 25;
String FilePath = "D:\dev\Test.txt";
Serialize(TestVariable, FilePath);
// [...]
// at some later point in the code, when I want to access the file
Deserialize(&TestVariable, FilePath);
我已经听说过像 Boost 这样的库,但我认为当我只想简单地序列化时,这有点 overkill变量。
已经预先感谢您的回答。 :D
首先让我列出不这样做的原因:
- 在不同的机器上重复使用这些文件是不安全的
- 速度可能比任何库都慢
- 像指针、映射或结构这样的复杂类型很难正确实现
但是如果你真的想做一些定制的事情,你可以简单地使用流,这里是一个使用 stringstream 的例子(我总是在我的单元测试中使用 stringstream 因为我希望它们很快),但你可以简单地修改它使用文件流。
请注意,反序列化模板函数使用的类型必须是默认可构造的。对于复杂的 类.
这一定是一个非常严格的要求
#include <sstream>
#include <iostream>
template<typename T>
void serialize(std::ostream& os, const T& value)
{
os << value;
}
template<typename T>
T deserialize(std::istream& is)
{
T value;
is >> value;
return value;
}
int main()
{
std::stringstream ss;
serialize(ss, 1353);
serialize(ss, std::string("foobar"));
std::cout << deserialize<int>(ss) << " " << deserialize<std::string>(ss) << std::endl;
return 0;
}
首先,有一点“不一致”:您要求在看起来像文本文件的文件中进行二进制序列化。我会假设你真的想要一个二进制输出。
序列化整数时唯一需要注意的是机器的字节序(尽管大多数机器都是小端)。
在 C++17 或更低版本中,最简单的方法是运行时检查,例如
inline bool littleEndian()
{
static const uint32_t test = 0x01020304;
return *((uint8_t *)&test) == 0x04;
}
C++20 引入了编译时检查,因此您可以将之前的重写为
constexpr bool littleEndian()
{
return std::endian::native == std::endian::little;
}
此时你想要的是以标准方式编写所有整数。
通常 BigEndian 是标准。
template <typename T>
inline static T revert(T num)
{
T res;
for (std::size_t i = 0; i < sizeof(T); i++)
((uint8_t *)&res)[i] = ((uint8_t *)&num)[sizeof(T) - 1 - i];
return res;
}
此时您的序列化程序将是:
template <typename T>
void serialize(T TestVariable, std::string& FilePath)
{
static_assert(std::is_integral<T>::value); //check that T is of {char, int, ...} type
static_assert(!std::is_reference<T>::value); //check that T is not a reference
std::ofstream o(FilePath);
if (littleEndian())
TestVariable = revert(TestVariable);
o.write((char *)&TestVariable, sizeof(T));
}
你的反序列化器将是
template <typename T>
void deserialize(T *TestVariable, std::string FilePath)
{
static_assert(std::is_integral<T>::value);
std::ifstream i(FilePath);
i.read((char *)TestVariable, sizeof(T));
if (littleEndian())
*TestVariable = revert(*TestVariable);
}
注意:此代码只是适用于您的界面的示例,您只需包含 <iostream>
、<fstream>
,如果您使用的是 c++20 版本,请包含 <bit>
所以,我想在 C++ 中为一些 int 变量实现简单的序列化,但我真的不知道如何...
我的目标如下:
我基本上希望能够将任何整数转换为二进制,最好是通过简单的函数调用。
// Here´s some dummy code of what I essentially want to do
int TestVariable = 25;
String FilePath = "D:\dev\Test.txt";
Serialize(TestVariable, FilePath);
// [...]
// at some later point in the code, when I want to access the file
Deserialize(&TestVariable, FilePath);
我已经听说过像 Boost 这样的库,但我认为当我只想简单地序列化时,这有点 overkill变量。
已经预先感谢您的回答。 :D
首先让我列出不这样做的原因:
- 在不同的机器上重复使用这些文件是不安全的
- 速度可能比任何库都慢
- 像指针、映射或结构这样的复杂类型很难正确实现
但是如果你真的想做一些定制的事情,你可以简单地使用流,这里是一个使用 stringstream 的例子(我总是在我的单元测试中使用 stringstream 因为我希望它们很快),但你可以简单地修改它使用文件流。
请注意,反序列化模板函数使用的类型必须是默认可构造的。对于复杂的 类.
这一定是一个非常严格的要求#include <sstream>
#include <iostream>
template<typename T>
void serialize(std::ostream& os, const T& value)
{
os << value;
}
template<typename T>
T deserialize(std::istream& is)
{
T value;
is >> value;
return value;
}
int main()
{
std::stringstream ss;
serialize(ss, 1353);
serialize(ss, std::string("foobar"));
std::cout << deserialize<int>(ss) << " " << deserialize<std::string>(ss) << std::endl;
return 0;
}
首先,有一点“不一致”:您要求在看起来像文本文件的文件中进行二进制序列化。我会假设你真的想要一个二进制输出。
序列化整数时唯一需要注意的是机器的字节序(尽管大多数机器都是小端)。
在 C++17 或更低版本中,最简单的方法是运行时检查,例如
inline bool littleEndian()
{
static const uint32_t test = 0x01020304;
return *((uint8_t *)&test) == 0x04;
}
C++20 引入了编译时检查,因此您可以将之前的重写为
constexpr bool littleEndian()
{
return std::endian::native == std::endian::little;
}
此时你想要的是以标准方式编写所有整数。 通常 BigEndian 是标准。
template <typename T>
inline static T revert(T num)
{
T res;
for (std::size_t i = 0; i < sizeof(T); i++)
((uint8_t *)&res)[i] = ((uint8_t *)&num)[sizeof(T) - 1 - i];
return res;
}
此时您的序列化程序将是:
template <typename T>
void serialize(T TestVariable, std::string& FilePath)
{
static_assert(std::is_integral<T>::value); //check that T is of {char, int, ...} type
static_assert(!std::is_reference<T>::value); //check that T is not a reference
std::ofstream o(FilePath);
if (littleEndian())
TestVariable = revert(TestVariable);
o.write((char *)&TestVariable, sizeof(T));
}
你的反序列化器将是
template <typename T>
void deserialize(T *TestVariable, std::string FilePath)
{
static_assert(std::is_integral<T>::value);
std::ifstream i(FilePath);
i.read((char *)TestVariable, sizeof(T));
if (littleEndian())
*TestVariable = revert(*TestVariable);
}
注意:此代码只是适用于您的界面的示例,您只需包含 <iostream>
、<fstream>
,如果您使用的是 c++20 版本,请包含 <bit>