Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > C/C++ > stl实现序列化
【标  题】:stl实现序列化
【关键字】:stl
【来  源】:http://blog.csdn.net/smile_stone/archive/2006/12/08/1434269.aspx

stl实现序列化

Your Ad Here

        copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));

    }

    return 0;

}

////////////////////////////////////////////////////////////////////////////////

//该程序的输出如下:

/*******************************************************************************

1 2 3 4 5

*******************************************************************************/

//data.txt中的内容如下:

/*******************************************************************************

1 2 3 4 5

*******************************************************************************/

////////////////////////////////////////////////////////////////////////////////

#endif//CODE1

#if 0

    很明显我们在应用程序中保存了数据的类型信息,如:文件中的[1,2,3,4,5]的类型“

int”信息是保存在程序中的,这一点是和其它的序列化方案有着极大的不同,用过MFC的

都知道,MFC中为了实现序列化功能,必须将所有的类型信息和数据信息同时保存在文件中

,虽然都是以二进制格式的形式,但是通过二进制编辑器可以很容易的看出你面保存的类

型信息字符串,这一点是有安全隐患的。所以从安全和保密上讲,本文中的方式是MFC序列

化机制所不能够做到的。从代码简洁程度和序列化文件的格式简单性来讲,本文中的方案

也绝对不是MFC的序列化所能够轻易做到的。在考察Boost的serialize库的时候,发现文件

中也保存了类型信息。

    讨论到了这里,你也许会说,这里只有一种类型的数据,如果类型多了,还能够用这

种方式实现序列化么。可以非常肯定的告诉你,我已经成功的使用过这种方式实现了序列

化了。下面来看一个非常直接的例子:

#endif

#if CODE2

////////////////////////////////////////////////////////////////////////////////

//模拟程序序列化的简单代码

#include //cout

#include //ofstream,ifstream

#include //istringstream

#include //string

#include //vector

#include //ostream_iterator,istream_iterator,back_inserter

#include //partial_sum

#include //copy

using namespace std;

const char delimiter = '*';//用来分隔多种数据类型的分隔符

int main()

{

    {//从程序序列化到文件

        //v1,v2,v3,v4,v5用来模拟应用程序中的许多类型的数据,当然类型信息可以

        //是任意的类型,当然需要为每一种类型书写各自的operator<<和operator>>

        //运算符啦!具体的情况具体分析,熟悉STL的人自然可以根据本文中的各个

        //STL算法和容器的要求写出必须的函数和操作符了。

        vector<int>     v1(3,1);//3个1

        vector<short>   v2(4,2);//4个2

        vector<long>    v3(5,3L);//5个3

        vector<float>   v4(6,4.1);//6个4.1

        vector<double>  v5(7,5.2);//7个5.2

        //一下的代码用来产生不同的类型序列

        partial_sum(v1.begin(),v1.end(),v1.begin());//[1,2,3]

        partial_sum(v2.begin(),v2.end(),v2.begin());//[2,4,6,8]

        partial_sum(v3.begin(),v3.end(),v3.begin());//[3L,6L,9L,12L,15L]

        partial_sum(v4.begin(),v4.end(),v4.begin());//[4.1,8.2,12.3,16.4,20.5,24.6]

        partial_sum(v5.begin(),v5.end(),v5.begin());//[5.2,10.4,15.6,20.8,26.0,31.2,36.4]

        ofstream out("data.txt");//生成文件输出流

        //将数组v中的数据全部输出到文件流中,这种操作在C++中成为文件操作

        //在这里暂时称为序列化到文件操作。实际上这里为了简单序列化的格式

        //为文本文件格式。如果需要其它的格式完全可以通过自定义输出流游标

        //的方式,或者重载运算符operator<<和operator>>实现不同的序列化格

        //式。可以参见本人的其它相关文档。

        //向文件中依次序列化所有的应用程序数据

        copy(v1.begin(),v1.end(),ostream_iterator<int   >(out," "));

        out << delimiter << endl;//输出分隔符分开不同的数据类型

        copy(v2.begin(),v2.end(),ostream_iterator<short >(out," "));

        out << delimiter << endl;//输出分隔符分开不同的数据类型

        copy(v3.begin(),v3.end(),ostream_iterator<long  >(out," "));

        out << delimiter << endl;//输出分隔符分开不同的数据类型

        copy(v4.begin(),v4.end(),ostream_iterator<float >(out," "));

        out << delimiter << endl;//输出分隔符分开不同的数据类型

        copy(v5.begin(),v5.end(),ostream_iterator<double>(out," "));

    }

    {//从文件序列化到程序

        //v1,v2,v3,v4,v5用来模拟应用程序中的许多类型的数据

        vector<int>     v1;

        vector<short>   v2;

        vector<long>    v3;

        vector<float>   v4;

        vector<double>  v5;

        ifstream in("data.txt");//建立文件输入流

        //从文件中依次提取出序列化到文件的所有的数据

        copy(istream_iterator<int   >(in),istream_iterator<int   >(),back_inserter(v1));

        in.clear();in.ignore(10,delimiter);//让流恢复状态继续提取数据

        copy(istream_iterator<short >(in),istream_iterator<short >(),back_inserter(v2));

        in.clear();in.ignore(10,delimiter);//让流恢复状态继续提取数据

        copy(istream_iterator<long  >(in),istream_iterator<long  >(),back_inserter(v3));

        in.clear();in.ignore(10,delimiter);//让流恢复状态继续提取数据

        copy(istream_iterator<float >(in),istream_iterator<float >(),back_inserter(v4));

        in.clear();in.ignore(10,delimiter);//让流恢复状态继续提取数据

        copy(istream_iterator<double>(in),istream_iterator<double>(),back_inserter(v5));

        //下面的5行代码仅仅只是为了显示是否真的被序列化到了程序中

        copy(v1.begin(),v1.end(),ostream_iterator<int   >(cout," "));cout<        copy(v2.begin(),v2.end(),ostream_iterator<short >(cout," "));cout<        copy(v3.begin(),v3.end(),ostream_iterator<long  >(cout," "));cout<        copy(v4.begin(),v4.end(),ostream_iterator<float >(cout," "));cout<        copy(v5.begin(),v5.end(),ostream_iterator<double>(cout," "));cout<    }

    return 0;

}

////////////////////////////////////////////////////////////////////////////////

//该程序的输出如下:

/*******************************************************************************

1 2 3

2 4 6 8

3 6 9 12 15

4.1 8.2 12.3 16.4 20.5 24.6

5.2 10.4 15.6 20.8 26 31.2 36.4

*******************************************************************************/

//data.txt中的内容如下:

/*******************************************************************************

1 2 3 *

2 4 6 8 *

3 6 9 12 15 *

4.1 8.2 12.3 16.4 20.5 24.6 *

5.2 10.4 15.6 20.8 26 31.2 36.4

*******************************************************************************/

////////////////////////////////////////////////////////////////////////////////

#endif//CODE2

#if 0



    很明显,CODE2中的代码段已经满足了我们的序列化要求。已经可以序列化各种不同类型

的数据,虽然CODE2中使用的是基本类型中的5种情况,但是由于C++的特色,对于类这样的扩

展类型完全可以象基本类型一样来对待,至于怎样才能够象基本类型一样来对待,这是C++基

础知识,基本上就是重载C++运算符。



    有人或许会说:上面的方法并不能够处理指针容器(容器中放置的是指针而不是对象)

实际上这是一种误导,虽然上面的代码中看不到指针的东西,但是STL中确确实实是采用的动

态内存分配的方式实现对象管理的,我们在使用STL的过程中实际上已经让STL替我们管理了

麻烦不断的内存指针问题!更确切点说,STL的游标概念就是泛化的指针。尽管如此,我们还

是要避免在容器中使用指针,虽然STL允许这么做,但是我并不提倡这一点,因为不用指针已

经可以很好的实现自己想要实现的任何功能了(当然这仅仅只是限于本文所介绍的序列化方

案)。对于其它的C++功能方面指针还是有它独到的能力,就我的使用经验来说,不用指针完

全可以实现指针所能够实现的所有功能,当然这里面包含了许许多多的C++高级知识,能够用

指针方便实现的当然还是用指针实现的好啊:)



    在这里作为提示,给出如果非要使用指针容器的情况如何实现序列化的方法:对指针容

器进行特殊处理,序列化到文件的时候一定要保证并不是把指针所指的对象序列化到了文件

而是将该指针在原来的对象容器中的索引保存到文件,从文件提取数据的时候同样是根据索

引值到对象容器中查找到对象并得到相应的指针放到指针容器中。从本段前面的讨论可以知

道:如果存在某个指针容器,就一定存在对应的对象容器,并且,在序列化输出和序列化输

入的时候都是先序列化的对象容器,然后才是指针容器,下面的CODE3中给出了具体的实例

代码:



#endif

#ifdef CODE3

////////////////////////////////////////////////////////////////////////////////

//模拟程序序列化的简单代码

#include //cout

#include //ofstream,ifstream

#include //vector

#include //ostream_iterator,istream_iterator,back_inserter

#include //partial_sum

#include //copy

#include

#include

#include

#include

using namespace std;

//下面是针对输入和输出专门写的序列化模板

template<class Container>

ofstream& operator << (ofstream&out,Container&c)

{

    typedef typename Container::value_type T;

    copy(c.begin(),c.end(),ostream_iterator(out," "));

    out << endl;

    return out;

}

template<class Container>

ifstream& operator >> (ifstream&in,Container&c)

{

    typedef typename Container::value_type T;

    string buffer;//每一行数据的临时缓冲区

    getline(in,buffer);//从文件中读取一行数据到缓冲区中

    istringstream isin(buffer);//构造输入字符串流

    copy(istream_iterator(isin),istream_iterator(),back_inserter(c));

    return in;

}

template<class Container,class PointerContainer>

ofstream& operator << (ofstream&out,pair p)

{

    Container&c         = *(p.first);

    PointerContainer&cp = *(p.second);

    typename PointerContainer::iterator it = cp.begin();

    for(;it!=cp.end();++it)

    {

        typename Container::iterator itc;

        for(;itc!=c.end();++itc){

            if(&(*itc)==*it) out << distance(c.begin(),itc) << " " ;

        }

    }

    out << endl;

    return out;

}

template<class Container,class PointerContainer>

ifstream& operator >> (ifstream&in,pair p)

{

    Container&c         = *(p.first);

    PointerContainer&cp = *(p.second);

    typedef typename Container::value_type T;

    string buffer;//每一行数据的临时缓冲区

    getline(in,buffer);//从文件中读取一行数据到缓冲区中

    istringstream isin(buffer);//构造输入字符串流

    size_t tmp;//用来临时保存读取的索引号

    while(isin >> tmp)//读取成功isin状态表示成功

    {

        typename Container::iterator it = c.begin();

        advance(it,tmp);//将游标移动到指定的索引位置

        cp.push_back(&(*it));//将这个对象的地址保存到地址数组中

    }

    return in;

}



int main()

{

    {//从程序序列化到文件

        vector<int> v(5,1);//[1,1,1,1,1]

        vector<int*> vp;//指针容器

        vp.push_back(&v[1]);

        vp.push_back(&v[3]);

        partial_sum(v.begin(),v.end(),v.begin());//[1,2,3,4,5]

        ofstream out("data.txt");//生成文件输出流

        //将数组v中的数据全部输出到文件流中,这种操作在C++中成为文件操作

        //在这里暂时称为序列化到文件操作。实际上这里为了简单序列化的格式

        //为文本文件格式。如果需要其它的格式完全可以通过自定义输出流游标

        //的方式,或者重载运算符operator<<和operator>>实现不同的序列化格

        //式。可以参见本人的其它相关文档。

        out << v << make_pair(&v,&vp) ;

    }

    {//从文件序列化到程序

        vector<int> v;//模拟应用程序中数据

        vector<int*> vp;//指针容器

        ifstream in("data.txt");//建立输入流

        //下面的这行代码从文件中提取数据到v中,模拟了应用程序的序列化过程

        in >> v >> make_pair(&v,&vp) ;

        //下面的这行代码仅仅只是为了显示是否真的被序列化到了程序中

        copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));

        cout << endl;

        //输出指针数组中指向的对象数据

        struct X{static void print(const int*ptr){cout<<*ptr<<" ";}};

        for_each(vp.begin(),vp.end(),X::print);

    }

    return 0;

}

////////////////////////////////////////////////////////////////////////////////

//该程序的输出如下:

/*******************************************************************************

1 2 3 4 5

2 4

*******************************************************************************/

//data.txt中的内容如下:

/*******************************************************************************

1 2 3 4 5

1 3
 
ldexp ( )【C语言库函数源代码】:【上一篇】
C++学习:在C++中创建持久对象:【下一篇】
【相关文章】
  • 在linux下一个有趣的STL文件IO问题
  • C++ STL(标准模板库) 学习资源列表
  • 理解STL中的函数子,函数子类,和其用法
  • std::string及iostream实现性能比较:stlport VS GNU libstdc++
  • 使用C++(STL)+Cgicc+OTL+prototype开发简易CGI留言本(2)
  • stl 容器(1)
  • stl 容器(2)
  • Castle ActiveRecord中ntext类型的映射
  • stl中的异常
  • STL容器的拷贝构造和赋值特性
  • 【随机文章】
  • 注册码是怎样炼成的(2)
  • An Introduction to Boost:Preface
  • 基于.Net Framework的N层分布式应用开发
  • 从新浪网下载视频文件
  • 如何进行阳台装饰
  • gentoo 下面 emerge gcc 4.0.2
  • mysql优化编译安装
  • linux下面让firefox支持java
  • windows xp系统取消登录时选择用户自动登录xp
  • Customize User Configurations
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.