反序列化数据。

 收藏

我目前使用它来序列化数据,将其写入共享内存,以便另一个程序可以重建它并使用它:

template<typename T>
void Serialize(unsigned char* &Destination, const T &Source)
{
    CopyMemory(Destination, &Source, sizeof(T));
    //Destination += sizeof(T);  //Not sure if to add this or not.
}

template<typename T>
void Serialize(unsigned char* &Destination, const std::vector<T> &VectorContainer)
{
    size_t Size = VectorContainer.size();
    Serialize(Destination, Size);
    for (size_t I = 0; I < Size; ++I)
        Serialize(Destination, VectorContainer[I]);
}

template<typename T>
void DeSerialize(unsigned char* &Destination, const T& Source, size_t Size)
{
    CopyMemory(Destination, &Source, Size);
}

template<typename T>
void DeSerialize(std::vector<T>* &VectorContainer, const T &Source, size_t ContainerSize, size_t ByteSize)
{
    VectorContainer.resize(ContainerSize);
    CopyMemory(VectorContainer, &Source, ByteSize);
}

I'm not sure if my DeSerialize is correct though. The data I want to deserialize looks like: http://www.daniweb.com/software-development/cpp/threads/430518/shared-memory-objects-across-dlls

我应该如何反序列化它?

我试过了:

DeSerialize(ListOfFonts, Data[7], sizeof(FontChar));
return &ListOfFonts[0];  //Return a void* to my vector containing the reconstructed data.
回复
  • Liz 回复

    您可以这样创建一个非常简单的序列化器:(警告:这既不健壮,也不可用,至少不符合我的标准)

    #include <fstream>
    
    class iserializer {
      private:
        std::ifstream in_file;
      public:
    
        iserializer(const std::string& aFileName) : in_file(aFileName.c_str(), std::ios_base::binary) { };
    
        template <typename T>
        friend
        iserializer& operator >>(iserializer& in_serial, T& value) {
          in_serial.in_file.read((char*)&value, sizeof(T));
          return in_serial;
        };
    };
    
    template <typename T, typename Allocator>
    iserializer& operator >>(iserializer& in_serial, std::vector<T,Allocator>& value) {
      typedef typename std::vector<T,Allocator>::size_type SizeType;
      SizeType sz;
      in_serial >> sz;
      value.reserve(sz);
      for(SizeType i = 0; i < sz; ++i) {
        T tmp = T();
        in_serial >> tmp;
        value.push_back(tmp);
      };
      return in_serial;
    };
    
    template <typename T, typename Allocator>
    iserializer& operator >>(iserializer& in_serial, std::list<T,Allocator>& value) {
      typedef typename std::list<T,Allocator>::size_type SizeType;
      SizeType sz;
      in_serial >> sz;
      for(SizeType i = 0; i < sz; ++i) {
        T tmp = T();
        in_serial >> tmp;
        value.push_back(tmp);
      };
      return in_serial;
    };
    
    class oserializer {
      private:
        std::ofstream out_file;
      public:
    
        oserializer(const std::string& aFileName) : out_file(aFileName.c_str(), std::ios_base::binary) { };
    
        template <typename T>
        friend
        oserializer& operator <<(oserializer& out_serial, const T& value) {
          out_serial.out_file.write((const char*)&value, sizeof(T));
          return out_serial;
        };
    };
    
    template <typename T, typename Allocator>
    oserializer& operator <<(oserializer& out_serial, const std::vector<T,Allocator>& value) {
      typedef typename std::vector<T,Allocator>::const_iterator Iter;
      out_serial << value.size();
      for(Iter it = value.begin(); it != value.end(); ++it)
        out_serial << (*it);
      return out_serial;
    };
    
    template <typename T, typename Allocator>
    oserializer& operator <<(oserializer& out_serial, const std::list<T,Allocator>& value) {
      typedef typename std::list<T,Allocator>::const_iterator Iter;
      out_serial << value.size();
      for(Iter it = value.begin(); it != value.end(); ++it)
        out_serial << (*it);
      return out_serial;
    };
    

    Then, your custom classes or struct simply need to overload the << and >> operator, just like you would for iostreams:

    struct Model
    {
        GLint SX, SY;
        GLuint Stride;
        unsigned long ID;
        GLint TriangleCount;
        GLboolean NullVertex;
        GLboolean ShowVertices;
        //const GLvoid* VertexPointer; // can't deal with that, should be a vector instead.
        std::vector<Vector3D> Vertices;
    };
    
    iserializer& operator >>(iserializer& in_serial, Model& mdl) {
      return in_serial >> mdl.SX >> mdl.SY 
                       >> mdl.Stride 
                       >> mdl.ID 
                       >> mdl.TriangleCount 
                       >> mdl.Vertices;
    };
    
    oserializer& operator <<(oserializer& out_serial, const Model& mdl) {
      return out_serial << mdl.SX << mdl.SY 
                        << mdl.Stride 
                        << mdl.ID 
                        << mdl.TriangleCount 
                        << mdl.Vertices; 
    };
    

    If you don't want to use file-stream objects, you can certainly use whatever else allows for binary read/write. You could also make the iserializer/oserializer classes into base-classes for any type of output (file, memory, etc.), but that can get a bit more complicated (because virtual functions cannot be templated), which is basically what I did with my iarchive/oarchive classes in my library (you can see all the protected virtual functions for each type of primitive, which all have to be implemented in derived classes).

  • 怪叔叔 回复

    Hey I've edited your code if you don't mind me using it. It works quite well. I was reading: http://www.mr-edd.co.uk/blog/beginners_guide_streambuf for the last couple hours to learn how to use my own streams.

    我将您的更改为:

    std::istringstream in_file;
    
    public:
    
    iserealizer(const void *Buffer, size_t Size)
    {
    int_file.rdbuf()->pubsetbuf((char*)Buffer, Size);
    };
    

    加上我从streambuf和东西派生而来,并按照您的建议添加到了类中。这很有趣:)似乎可以很好地满足我的需求。谢谢。

  • et_et 回复

    First of all, you should not use template specialization of function templates. Here is an explanation why. You must use overloading instead. So, your "Model" Serialize function should just be a straight overload:

    void Serialize(unsigned char* &Destination, const Model& M) {
        Serialize(Destination, M.SX);
        Serialize(Destination, M.SY);
        Serialize(Destination, M.Stride);
        Serialize(Destination, M.ID);
        Serialize(Destination, M.TriangleCount);
        Serialize(Destination, M.Vertices);
    };
    

    Second, when doing serialization, you will need more complexity than that because you'll have trouble with more complex cases. Usually, one would create a "serializer" class (and possibly a separate input and output serializer class) that acts pretty much like iostreams in standard C++ libraries. In the same way as you can make you classes (or structs) outputtable and inputtable to and from a standard iostream object (by overloading the << and >> operators), you do the same for your serialization code.

    The general idea when doing serialization is that the mechanism for deserializing should be the exact opposite of the process of serializing. It is also a good idea, generally, to allow for more flexibility in the destination of the serialization such that you can use the same serialize/deserialize code for many purposes, such as saving/loading in files (of different formats), sending/receiving objects across a network, or sharing data between DLLs (modules). I suggest you take a look at some of the existing serialization libraries and get inspiration from that. Two examples I can think of are Boost.Serialization and my own serialization library (part of a bigger library), they both work in a very similar fashion:

    • 输入序列化器和输出序列化器的基类。
    • 序列化/反序列化对象(原始或自定义类)的标准函数(或机制),可以为任何特殊类型重载。
    • 如果您要创建要序列化的自定义类,则要继承的基类。
    • 一种用于标识动态类型的方法(例如,类似于RTTI系统)和一种用于构造任何类型的动态类型的对象的方法(源自可序列化的基类)。
    • 展平对象层次结构的机制,这样在每个序列化的数据流中多个交叉引用的对象不会被序列化一次以上。
    • 一组输入/输出序列化器(从序列化器的基类派生),用于不同类型的基础输出(xml或二进制文件,网络数据包,标准序列化格式,如JSON或“ Google协议缓冲区”(或protobuf)),或二进制内存映射文件)。

  • 妾随 回复

    我添加了这个:

    template<>
    void Serialize<Model>(unsigned char* &Destination, const Model &M)
    {
        Serialize(Destination, M.SX);
        Serialize(Destination, M.SY);
        Serialize(Destination, M.Stride);
        Serialize(Destination, M.ID);
        Serialize(Destination, M.TriangleCount);
        Serialize(Destination, M.Vertices);
    }
    
    
    void* GetData()
    {
        unsigned char* Data = reinterpret_cast<unsigned char*>(LD);     //The long double that holds the map memory.
        ListOfData.resize(LD[2]);                                       //LD[2] holds the size of the original vector.
        CopyMemory(&ListOfData[0], Data, sizeof(Model) * LD[2]);
    
        return &ListOfData[0];
    }
    

  • 转身说再见 回复

    嗯,但这就是问题所在。我无法使用Boost /库。自从我安装了它之后,我就不能了。

    这就是为什么我只写了复印要点。我很难读回它。特别是对于矢量。

    我打算将ostream和istream与rdbuf一起使用,但是考虑到我可能拥有大量信息的结构向量,因此它会通过文本来进行处理。

    I thought CopyMemory would be better. I was reading: http://ideone.com/boBt3 and http://www.ocoudert.com/blog/2011/07/09/a-practical-guide-to-c-serialization/

    和很多指南,但它们似乎都是针对Java和支持本机这种东西的语言或Boost。 我也在考虑使用可变参数模板向其传递应序列化的数据(结构的任意数量的数据成员)。