我有一系列类只包含以下类型的变量:std :: string,int,double。我应该能够将这些类的对象序列化/反序列化为C字符串(以null结尾)。我不想使用一些3rdparty序列化器,也不想自己编写全功能的序列化器。我将在代码中仅序列化/反序列化一次。
那么,如何编写非常小巧而优雅的序列化器并快速完成它?
更新
我已经编写并测试了我自己的。也许对某人有用。如果您发现一些错误或有一些建议如何让它变得更好,请告诉我。这是:
typedef std::ostringstream ostr;
typedef std::istringstream istr;
const char delimiter = '\n';
const int doublePrecision = 15;
void Save(ostr& os, int x) { os << x << delimiter; }
void Save(ostr& os, double x)
{
os.precision(doublePrecision);
os << x << delimiter;
}
void Save(ostr& os, const std::string& x) { os << x << delimiter; }
void Load(istr& is, int& x)
{
is >> x;
is.rdbuf()->sbumpc(); // get rid of delimiter
}
void Load(istr& is, double& x)
{
is >> x;
is.rdbuf()->sbumpc(); // get rid of delimiter
}
void Load(istr& is, std::string& x) { getline(is, x, delimiter); }
测试:
std::string a = "Test string 1 2 and 2.33";
std::string b = "45";
double c = 45.7;
int d = 58;
double e = 1.0/2048;
std::ostringstream os;
Save(os, a);
Save(os, b);
Save(os, c);
Save(os, d);
Save(os, e);
std::string serialized = os.str();
std::string aa;
std::string bb;
double cc = 0.0;
int dd = 0;
double ee = 0.0;
std::istringstream is(serialized);
Load(is, aa);
Load(is, bb);
Load(is, cc);
Load(is, dd);
Load(is, ee);
ASSERT(a == aa);
ASSERT(b == bb);
ASSERT(c == cc);
ASSERT(d == dd);
ASSERT(e == ee);
答案 0 :(得分:1)
有两种方法可以将字符串数据序列化为流,您可以使用C样式并使用null来终止它,或者(更便携且更容易阅读)首先输出一个字节,该字节表示字符串的长度写字符串。
现在,如果你想区分一个字符串和一个非字符串(在这种情况下是数字),你可以在每个“数据包”(项目)前加一个字节代码,比如0x00表示int,0x01表示double,0x02表示字符串,并根据代码分支关闭分支。这样你甚至可以将int / double写成一个字节,这样你就不会失去精度,你最终也会得到一个更小/更容易阅读的文件。
答案 1 :(得分:0)
void save(std::ostringstream& out, const std::string& x)
{
out << x;
}
void read(std::istringstream& in, std::string& x)
{
in.str(x);
}
来自here。
答案 2 :(得分:0)
我知道您不想使用3rdParty序列化程序,但如果您要重新考虑:使用Boost.Serialization。
(即使这不是你的答案,也可能是其他人在这个问题上磕磕绊绊)
很简单的例子
class some_data
{
public:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & my_string;
ar & my_double;
}
private:
std::string my_string;
double my_double;
};
然后保存:
my_data dataObject;
std::ofstream ofs("filename");
boost::archive::text_oarchive oa(ofs);
oa << dataObject;
或加载:
my_data dataObject;
std::ifstream ifs("filename");
boost::archive::text_iarchive ia(ifs);
ia >> dataObject;
答案 3 :(得分:0)
请参阅sun xdr格式。它是二元和高效的。
我有一个很小的自定义类来做这个,例如:
Marshall& Marshall::enc(const string& str) {
size_t size = str.size();
size_t pad = (4 - (size%4))%4;
size_t size_on_buff = size + pad;
space_for(sizeof(uint32_t) + size + pad);
check_size_t_overflow(size);
enc(static_cast<uint32_t>(size));
// xdr mandates padding
//space_for(size_on_buff);
memcpy(&(*buff)[pos],str.data(), size);
memset(&(*buff)[pos+size],0,pad);
pos+=size_on_buff;
return *this;
}
Marshall& Marshall::dec(string& str) {
str.clear();
size_t size;
dec(size);
size_t pad = (4 - (size%4))%4;
size_t size_on_buff = size + pad;
ck_space_avl(size + pad);
//str.resize(size);
str.assign((char*)&(*buff)[pos],size);
pos+=size_on_buff;
return *this;
}