自行开发高效精简的二进制序列化库(支持精简框架集)

06年开发基于Window CE的嵌入式组态软件时就曾遇到序列化问题,由于程序运行在Window CE平台,其上的.Net Compact Framework仅支持XML序列化,而XML序列化不仅序列化后的体积较大,而且执行时间较长(参见我以前写的文章:嵌入式组态环境升级及XML反序列化慢的困惑如何加速XML反序列化(精简框架集2.0SP1,WinCE4.2))。

而当时支持.Net Compact Framework的二进制序列化就是CompactFormatter(参见黎波的文章: .NET Compact Framework 2.0 中使用序列化)了,由于是第三方所开发,功能上尚不完善,故没有选用。

前段时间看MSN Direct代码,发现使用.Net Micro Framework二进制序列化后的广播数据比较小,并且速度快。所以想办法把相关代码做了平台移植,可没有想到的是在.net micro Framework.Net Framework中都可以正常运行的代码,在.NET Compact Framework中竟然不能运行(主要是对Assembly操作的相关函数支持不够)。

由于目前在.Net Compact Framework开发的应用逐渐增多,并且最近也打算升级原先开发的嵌入式组态软件,经过再三考虑决定自行开发支持精简框架集的二进制序列化(说明:.Net Micro Framework平台上的二进制序列化,由于运行在ARM系列的CPU上,会考虑一些大小端的问题,所以多于一个byte的值变量都要进行特殊处理,速度相对较慢,不过.Net Micro Framework二进制序列化的优点是,支持bit序列化(bool变量按位存取,也可以为其它变量指定位数),所以它的序列化结果是最精简的)。

.Net Micro Framework二进制序列化代码做参考,所以自行开发一个支持精简框架集二进制序列化库,并不是一件特别繁杂和痛苦的事:- 

在开发二进制序列化之前,对要完成的二进制序列化库,有以下几方面的考虑:

一、速度要快;

二、体积要小;

三、要支持自定义序列化;

针对第一点,故舍弃了.Net Micro Framework二进制序列化的bit序列化支持,并且精简了一些功能,比如仅支持原生数据类型的一维数组序列化,仅支持ArrayList,不支持泛型,此外不自行反射Assembly中的Type,和.Net Compact Framework XML序列化一样,需要开发者从外部传入Type列表;

针对第二点采用了很多.Net Micro Framework的二进制序列化思想,如序列化后的数据中不保存Type 的完整的名字,仅保存该名字的4个字节的哈希值,字符串的长度和数组长度用变长的1~4个字节的空间来保存,多个对象引用相同,仅保存首个对象等等;

而第三点主要和我开发的嵌入式组态功能相关,大量的图元派生于基类图元,而基类中的大量属性,在不同的图元中用到的都不同,如果一概而论全部序列化,则结果会比较大,而采用自定义序列化就能很好地解决这个问题。此外值得一提的是.Net Micro Framework二进制序列化和.Net Compact Framework XML序列化都不支持该功能。 

用了我大约4天的时间,终于完成了.Net Compact Framework 二进制序列化的第一版V0.1,目前测试的结果还是令人满意的(以下结果是在windows平台下测试的,循环执行100次)。

1.Net Micro Framework binary serialize

Data Length    : 103 byte

Serialize Time   : 46 ms

Deserialize Time : 46 ms

2.Net Compact Framework xml serialize

Data Length    : 998 byte

Serialize Time   : 31545 ms

Deserialize Time : 34092 ms

3CompactFormatterPlus binary serialize

Data Length    : 1598 byte

Serialize Time   : 103 ms

Deserialize Time : 132 ms

4.Net Framework binary serialize

Data Length    : 828 byte

Serialize Time   : 18 ms

Deserialize Time : 17 ms

5Yefan binary serialize

Data Length    : 113 byte

Serialize Time   : 8 ms

Deserialize Time : 8 ms 

     由以上可以看出,除了在体积上稍稍大于.Net Micro Framework的二进制序列化外,和其它序列化后的结果相比,几乎相差一个数量级,此外执行时间是最小的,并且其它相比,是几个数量级的差别。

在开发二进制序列化过程中发现,.Net Compact Framework xmlCompactFormatterPlus都不支持循环引用,如下面的类:

Class Test1

{

   Public int v1=0;

   Public Object o=null;

}

Test1 t=new Test1();

t.o=t;   //为自身

如果对t序列化,则.Net Compact Framework xmlCompactFormatterPlus都会出现异常,此外对CompactFormatterPlus,如果enum类型的基础类型不是默认的int型,也会抛出异常,如下面的枚举:

Enum Testbyte  {one ,two};

主要测试代码如下:

using  System;  
using  System.Collections.Generic;
using  System.ComponentModel;
using  System.Data;
using  System.Drawing;
using  System.Text;
using  System.Windows.Forms;
using  System.Collections;
using  System.IO;
using  System.Xml.Serialization;

namespace  CETest
{
    
public   partial   class  frmTest : Form
    {
        
public  frmTest()
        {
            InitializeComponent();
        }

        
private   void  btnTest_Click( object  sender, EventArgs e)
        {
            
#region  类型定义

            Type[] Types 
=   new  Type[] {  typeof (TestClass),  typeof (TestClass1),  typeof (TestClass2),  typeof (Color) };

            TestClass t1 
=   new  TestClass();
            t1.v1 
=   11 ;
            t1.v2 
=   22 ;
            t1.v3 
=   " 33 " ;
            t1.v4[
1 =   44 ;
            t1.v5[
0 =   " 55 " ;
            t1.v6 
=  TestClass.enumtest.enum2;
            t1.V7 
=   77 ;
            t1.v8.v1 
=   88 ;
            t1.v9 
=   new  TestClass2();
            t1.v9.v1 
=   99 ;
            t1.v10 
=  t1.v9;       // t1  循环引用  

            TestClass1 t11 
=   new  TestClass1();
            
// t11.v2.Add(t1);     // t1  循环引用
            t11.v2.Add( 3 );
            t11.v2.Add(
5 );
            t11.v1_base 
=   123 ;

            TestClass2 t22 
=   new  TestClass2();
            t1.v11.Add(t11);
            t1.v11.Add(t22);
            t1.v11.Add(
1 );

            
// t1.v12 = Color.Green;

            
#endregion

            
string  strInfo  =   "" ;
            Application.DoEvents();
            
long  start  =   0 ;
            
double  tk1  =   0 , tk2  =   0 ;
            
byte [] bytData  =   null ;

            
int  Count  =   1 ;

            
// if (chkXML.Checked)
            {
                start 
=  DateTime.Now.Ticks;
                
for  ( int  i  =   0 ; i  <  Count; i ++ )
                {
                    MemoryStream ms 
=   new  MemoryStream();
                    XmlSerializer xmls 
=   new  XmlSerializer( typeof (TestClass), Types);
                    xmls.Serialize(ms, t1);
                    bytData 
=  ms.ToArray();
                    ms.Close();
                }
                tk1 
=  TimeSpan.FromTicks(DateTime.Now.Ticks  -  start).TotalMilliseconds;
                start 
=  DateTime.Now.Ticks;
                
for  ( int  i  =   0 ; i  <  Count; i ++ )
                {
                    MemoryStream ms 
=   new  MemoryStream(bytData);
                    XmlSerializer xmls 
=   new  XmlSerializer( typeof (TestClass), Types);
                    TestClass obj2 
=  (TestClass)xmls.Deserialize(ms);
                    ms.Close();
                }
                tk2 
=  TimeSpan.FromTicks(DateTime.Now.Ticks  -  start).TotalMilliseconds;
                strInfo 
+=  ShowInfo( " .Net Compact Framework xml serialize " , bytData.Length, tk1, tk2);
            }

            
// if (chkCF.Checked)
            
// {
            
//     start = DateTime.Now.Ticks;
            
//     for (int i = 0; i < Count; i++)
            
//     {
            
//         MemoryStream ms = new MemoryStream();
            
//         CompactFormatter.CompactFormatter cf = new CompactFormatter.CompactFormatter();
            
//         cf.Serialize(ms, t1);
            
//         bytData = ms.ToArray();
            
//         ms.Close();

            
//     }
            
//     tk1 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds;
            
//     start = DateTime.Now.Ticks;
            
//     for (int i = 0; i < Count; i++)
            
//     {
            
//         MemoryStream ms = new MemoryStream(bytData);
            
//         CompactFormatter.CompactFormatter cf = new CompactFormatter.CompactFormatter();
            
//         TestClass obj3 = (TestClass)cf.Deserialize(ms);
            
//         ms.Close();
            
//     }
            
//     tk2 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds;
            
//     strInfo += ShowInfo("CompactFormatterPlus binary serialize", bytData.Length, tk1, tk2);
            
// }

            
// if (chkYFSoft.Checked)
            {
                start 
=  DateTime.Now.Ticks;
                
for  ( int  i  =   0 ; i  <  Count; i ++ )
                {
                    MemoryStream ms 
=   new  MemoryStream();
                    YFSoft.BinaryFormatter bf2 
=   new  YFSoft.BinaryFormatter(Types);
                    bf2.Serialize(ms, t1);
                    bytData 
=  ms.ToArray();
                    ms.Close();

                }
                tk1 
=  TimeSpan.FromTicks(DateTime.Now.Ticks  -  start).TotalMilliseconds;
                start 
=  DateTime.Now.Ticks;
                
for  ( int  i  =   0 ; i  <  Count; i ++ )
                {
                    MemoryStream ms 
=   new  MemoryStream(bytData);
                    YFSoft.BinaryFormatter bf2 
=   new  YFSoft.BinaryFormatter(Types);
                    TestClass obj4 
=  (TestClass)bf2.Deserialize(ms);
                    ms.Close();
                }
                tk2 
=  TimeSpan.FromTicks(DateTime.Now.Ticks  -  start).TotalMilliseconds;
                strInfo 
+=  ShowInfo( " Yefan binary serialize " , bytData.Length, tk1, tk2);
            }

            txtInfo.Text 
=  strInfo;
        }

        
private   string  ShowInfo( string  title,  int  length,  double  milliseconds1,  double  milliseconds2)
        {
            
string  strInfo  =   "" ;
            strInfo 
+=  title  +   " \r\n " ;
            strInfo 
+=   " Data Length      :  "   +  length.ToString()  +   " \r\n " ;
            strInfo 
+=   " Serialize Time   :  "   +  milliseconds1.ToString()  +   "  ms\r\n " ;
            strInfo 
+=   " Deserialize Time :  "   +  milliseconds2.ToString()  +   "  ms\r\n\r\n " ;
            
return  strInfo;
        }

    }

    [Serializable]
    
public   class  TestClassBase
    {
        
public   int  v1_base  =   111 ;
        
public   string  v2_base  =   " 222 " ;
    }

    [Serializable]
    
public   class  TestClass1 : TestClassBase
    {
        
public   int  v1  =   1 ;
        
public  ArrayList v2  =   new  ArrayList();
    }

    [Serializable]
    
public   class  TestClass2
    {
        
public   byte  v1  =   1 ;
        
public   string  v2  =   " 2 " ;
    }

    [Serializable]
    
public   class  TestClass  //  :YFSoft.ISerializable
    {
        
public   int  v1  =   1 ;
        [NonSerialized]
        
public   long  v2  =   2 ;
        
public   string  v3  =   " v3 " ;
        
public   int [] v4  =   new   int [ 3 ] {  0 1 2  };
        
public   string [] v5  =   new   string [ 2 ] {  " 123 " " 456 "  };
        
public   enum  enumtest :  int  { enum0, enum1, enum2 };   // :byte
         public  enumtest v6  =  enumtest.enum1;
        
private  UInt16 v7;
        
public  UInt16 V7 {  get  {  return  v7; }  set  { v7  =  value; } }
        
public  TestClass1 v8  =   new  TestClass1();
        
public  TestClass2 v9  =   null ;    //  new TestClass2();
         public   object  v10  =   null ;
        
public  ArrayList v11  =   new  ArrayList();
        
// public Color v12 = Color.Red;             

        
#region  ISerializable 成员
        
// public void GetObjectData(YFSoft.SerializationInfo si)
        
// {
        
//     v1 = si.GetInt32();
        
// }                         
        
// public void SetObjectData(YFSoft.SerializationInfo si)
        
// {
        
//     si.AddValue(v1);         
        
// }                         
         #endregion
    }
}

 下载地址:http://www.sky-walker.com.cn/yefan/YFSerializeTest.rar

转载于:https://www.cnblogs.com/yefanqiu/archive/2009/10/04/1577854.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值