微小的序列化器

时间:2009-09-30 10:38:24

标签: c++ serialization

我有一系列类只包含以下类型的变量: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);

4 个答案:

答案 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;
}