65.9K
CodeProject 正在变化。 阅读更多。
Home

STL 序列化库 (STL-SL)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.44/5 (15投票s)

2006 年 10 月 9 日

CPOL

4分钟阅读

viewsIcon

76433

downloadIcon

1124

STL 序列化库可以对 STL 对象进行序列化并从文件中加载。序列化文件格式可以根据您的需求进行定制。它快速、简单、免费!

快速用户指南

使用 STL 序列化库 (STL-SL) 是一个三步过程。第一步,您使用 STL-SL 声明要序列化的 STL 类型。

value_trait < int > int_filer;
value_trait < std::list< bool > > bool_list_filer;
value_trait < std::map<std::string, std::multimap< float, bool > > > complex_stl_filer;

在代码片段中,声明了三种不同的类型。每种类型都有不同程度的复杂性。int_filer 是所有中最简单的,其中 int 被参数化到 value_trait 模板类中。因此,int_filer 可用于序列化和从序列化文件中加载 int

类似地,bool_list_filer 的声明准备好序列化布尔类型列表。而 complex_stl_filer 准备一个 stringmultimap 数据类型的映射,其中 multimap 存储 floatbool 对,如上所示。

下一步,创建一个 file_interface,它需要一个序列化文件名,序列化数据将被写入/读取该文件。

stl_trait_writer file_interface (serialization_filename);

请注意,file_interface 在声明时不需要类型,这意味着不同类型的 STL 对象可能被序列化到同一个序列化文件中。

此外,由于序列化文件接口声明与数据文件声明无关,因此上述两个步骤可以互换位置。

在第三个也是最后一个阶段,数据被序列化到文件或从文件中加载。

filer.serialize ( stl_object, file_interface );

filer.load ( stl_object, file_interface );

以下代码片段说明了上述所有三个步骤的使用情况

//declare serialization-file interfaces
stl_trait_writer file_interface ( ".\\serialization-file.txt");

//declare the STL object 
std::vector < int > stl_object;


//declare the data filer 
value_trait < std::vector < int > > data_filer;


//...populate data in stl_object...// 
//serialize data in stl_object in the file pointed by file_interface
data_filer.serialize ( stl_object, file_interface );

//-- or --//

//load data in the file pointed by file_interface in stl_object STL object
data_filer.load ( stl_object, file_interface );
//...use data in stl_object...//

STL 序列化库

本文介绍了一组模板类,能够以用户定义的格式(默认是文本文件)序列化 STL 对象。

STL 序列化库由两大部分组成:序列化过滤器 (Serialization Filer) 和序列化模板类 (Serialization Template Classes)。

序列化过滤器

它包括以下三个类

//Serialization-file writer class.
//This guy writes the data to the file specified by 'file_path'.
//NOTE: This class does not recognize the data objects containing spaces, tabs, 
// new-line characters in them. This may be fixed by overloading '<<' operator and 
// adding escape-sequencing logic in it.
class stl_trait_writer: public std::ofstream
{
public:
      stl_trait_writer(const std::string& file_path):std::ofstream(file_path.c_str())
      {}
};

//Serialization-file reader class.
//This guy reads the data from the file specified by 'file_path'.
//NOTE: This class does not recognize the data objects containing spaces, tabs, 
// new-line characters in them. This may be fixed by overloading '>>' operator and 
// adding escape-sequencing logic in it.
class file_trait_reader: public std::ifstream
{
public:
      file_trait_reader(const std::string& file_path):std::ifstream(file_path.c_str())
      {}
};

//Serialization filer class.
//This guy presents the set of reader, writer objects responsible for reading and 
// writing to the serialization file.
template <class writer_trait , class reader_trait>
class filer_trait
{
public:
      typedef typename writer_trait writer_type;
      typedef typename reader_trait reader_type;
};

stl_trait_writerfile_trait_reader 类提供了基本的文件 I/O 机制。filer_trait 类是一个过滤器,它只配对上述两种类类型。另一种方法是让 filer_trait 类为了简单性实现文件 I/O 机制,但可能牺牲可伸缩性。

文件写入器类 (stl_trait_writer) 可以被用户定义的类替换,以将序列化文件格式更改为例如 XML。为从文件中加载序列化数据提供的文件读取器类 (file_trait_writer) 将需要修改为一个能够理解用户文件格式的类。

序列化模板类

此模块中的类集包含了将复杂的 STL 类型分解为基本类型以及序列化/反序列化基本数据类型的语言机制。

//Basic datatype serializer class.
//Triggers the read or write to the serialization file for the basic datatypes.
//NOTE: This class has been tweaked to work with the 'stl_trait_writer' class.
template <class val_trait, class val_filer_trait = 
              filer_trait<stl_trait_writer, file_trait_reader> >
class value_trait
{
public:
      typedef typename val_filer_trait::writer_type writer_trait;
      typedef typename val_filer_trait::reader_type reader_trait;

      void serialize(const val_trait& val, writer_trait &pen)
      {
            pen << val << "\n"; //a tweak for 'stl_trait_writer' class defined above.
            //pen << val; //correct code, this should replace above line of code should
                          //you choose to implement your own 'stl_trait_writer' class.

            pen.flush();
      }

      void load(val_trait& val, reader_trait &pen)
      {
            pen >> val;
      }
};

value_trait 类负责序列化和加载基本数据类型。上面展示的代码被调整为与上一节所述的序列化过滤器类一起使用。

以下摘录说明了将复杂 STL 类型分解为其基本组件的代码

//Sequence-list datatype serializer class.
//Triggers the read or write to the serialization file for the Sequence-list datatypes.
//This class takes care of STL types -- list, vector, stack, queue, deque
// and priority_queue
//NOTE: 'basic_string' type is not treated as sequence-list, but as basic type.
template <class sequence_list_type, class val_filer_trait >
class sequence_list_value_trait
{
public:
      typedef typename val_filer_trait::writer_type writer_trait;
      typedef typename val_filer_trait::reader_type reader_trait;

      typedef typename sequence_list_type::size_type size_type;   
      typedef typename sequence_list_type::value_type value_type;

      void serialize (sequence_list_type& val, writer_trait &pen )
      {
            value_trait<size_type, val_filer_trait> size_filer;
            size_filer.serialize (val.size(), pen);

            for(sequence_list_type::iterator i=val.begin(); i != val.end(); i++)
            {
                  value_trait<value_type, val_filer_trait> val_trait_key_filer;

                  val_trait_key_filer.serialize(*i,pen);
            }
      }

      void load (sequence_list_type& val, reader_trait &pen )
      {
            value_trait<size_type, val_filer_trait> size_reader;
            size_type val_size=0;
            size_reader.load(val_size, pen);

            for(; val_size > 0; val_size--)
            {
                  value_type element;

                  value_trait<value_type, val_filer_trait> val_trait_key_reader;

                  val_trait_key_reader.load(element, pen);

                  val.push_back(element);
            }
      }
};

sequence_list_value_trait 类将 listvectorstackqueuedequepriority_queue STL 类型分解为其更小的组件类型。因此,一个 int 类型的 vector 将被分解为 int 类型的一个 list,该列表由默认的 vector::iterator 类型进行迭代。而 int 类型的值由 value_trait 类进行序列化。

//Triggers the read or write to the serialization file for the Associative-list
// datatypes.
//This class takes care of STL types -- map, multimap, set, multiset
template <class associative_list_type, class val_filer_trait >
class associative_list_value_trait
{
public:

      typedef typename val_filer_trait::writer_type writer_trait;
      typedef typename val_filer_trait::reader_type reader_trait;

      typedef typename associative_list_type::size_type size_type;
      typedef typename associative_list_type::key_type key_type;
      typedef typename associative_list_type::mapped_type data_type;

      void serialize (associative_list_type& val, writer_trait &pen )
      {
            value_trait<size_type, val_filer_trait> size_filer;
            size_filer.serialize (val.size(), pen);

            for(associative_list_type::iterator i=val.begin(); i != val.end(); i++)
            {
                  value_trait<key_type, val_filer_trait> val_trait_key_filer;
                  value_trait<data_type, val_filer_trait> val_trait_data_filer;


                  val_trait_key_filer.serialize(i->first,pen);
                  val_trait_data_filer.serialize(i->second,pen);
            }
      }

      void load (associative_list_type& val, reader_trait &pen )
      {
            value_trait<size_type, val_filer_trait> size_reader;
            size_type val_size=0;
            size_reader.load(val_size, pen);

            for(; val_size > 0; val_size--)
            {
                  key_type key_element;
                  value_trait<key_type, val_filer_trait> val_trait_key_reader;
                  val_trait_key_reader.load(key_element, pen);

                  data_type data_element;
                  value_trait<data_type, val_filer_trait> val_trait_data_reader;
                  val_trait_data_reader.load(data_element, pen);

                  val.insert (std::pair<key_type, data_type> (key_element, data_element));
            }
      }
};

associative_list_value_trait 类是 sequence_list_value_trait 类的一个复杂版本,其中 mapmultimapsetmultiset STL 类型被分解为其键和数据元素类型,并根据需要进一步分解或序列化。

以下摘录描绘了复杂 STL 类型如何通过使用上面介绍的 associative_list_value_traitsequence_list_value_trait 类来启动分解过程的机制。

//STL vector datatype serializer class.
//Triggers the read or write to the serialization file for the STL vector datatype.
template <class val_trait_key, class val_trait_data, class val_filer_trait  > 
class value_trait< std::vector<val_trait_key, val_trait_data> , val_filer_trait  >
{
public:

      typedef typename val_filer_trait::writer_type writer_trait;
      typedef typename val_filer_trait::reader_type reader_trait;

      typedef std::vector<val_trait_key, val_trait_data> vector_value_trait;

      void serialize (vector_value_trait& val, writer_trait &pen )
      {
            sequence_list_value_trait<vector_value_trait, 
                     val_filer_trait> sequence_list_value_filer;
            
            sequence_list_value_filer.serialize (val, pen);
      }

      void load (vector_value_trait& val, reader_trait &pen )
      {

            sequence_list_value_trait<vector_value_trait, 
                     val_filer_trait> sequence_list_value_reader;

            sequence_list_value_reader.load (val, pen);
      }
};

以上代码段启动了 vector STL 类型到更小组件的分解过程,以便进一步序列化。对于 liststackqueuedequepriority_queue STL 类型,实现了类似的逻辑。

//STL multimap datatype serializer class.
//Triggers the read or write to the serialization file for the STL multimap datatype .
template <class val_trait_key, class val_trait_data, class val_filer_trait  > 
class value_trait< std::multimap<val_trait_key, val_trait_data> , val_filer_trait  > 
{
public:

      typedef typename val_filer_trait::writer_type writer_trait;
      typedef typename val_filer_trait::reader_type reader_trait;

      typedef std::multimap<val_trait_key, val_trait_data> multimap_value_trait;

      void serialize (multimap_value_trait& val, writer_trait &pen )
      {

            associative_list_value_trait<multimap_value_trait, 
                        val_filer_trait> associative_list_value_filer;

            associative_list_value_filer.serialize (val, pen);
      }

      void load (multimap_value_trait& val, reader_trait &pen )
      {

            associative_list_value_trait<multimap_value_trait, 
                        val_filer_trait> associative_list_value_reader;

            associative_list_value_reader.load (val, pen);
      }
};

就像上面处理将 vector 类型分解为更小组件的摘录一样,这段代码将 multimap 分解为其键类型和数据类型组件,以便进一步序列化。对于其他关联容器,如 mapsetmultiset,也可以实现类似的逻辑。

注释

需要注意的是,上面提供的库为 STL 过滤器声明中的每个子类型创建了一个类。虽然这不会产生额外的运行时开销,但它使命名空间中被序列化的类的数量加倍。如果类的数量超过了编译器支持的数量,您可能需要重构类层次结构。

上述事实可能被视为一个缺点,但值得注意的是,类的数量不会在运行时产生任何开销。其优点是 STL-SL 代码是类型安全的。

这里呈现的 STL-SL 是第一个修订版;您可能希望在序列化文件中包含被序列化的 STL 类型的类型信息,从而有助于 STL-SL 中的运行时类型检查。

还有其他库,例如 BOOST,它们功能更强大,但可能不那么直观。这些库解决了许多其他问题,如类版本控制、指针恢复和数据可移植性。本文的目的不是取代它们;本文应该被视为一个轻量级、易于使用的替代方案。此外,这里提供的代码可以看作是更完整序列化库实现的一个 STL 序列化引擎。

© . All rights reserved.