zoukankan      html  css  js  c++  java
  • 自行开发高效精简的二进制序列化库(支持精简框架集)

    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] { 012 };
            
    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

  • 相关阅读:
    开发中使用的一些小知识
    vue form表单验证
    团队作业8——第二次项目冲刺(Beta阶段)--第五天
    团队作业8——第二次项目冲刺(Beta阶段)--第四天
    团队作业8——第二次项目冲刺(Beta阶段)--第三天
    团队作业8——第二次项目冲刺(Beta阶段)--第二天
    团队作业8——第二次项目冲刺(Beta阶段)--第一天
    Beta版本冲刺计划及安排
    团队作业7——Alpha冲刺之事后诸葛亮
    团队作业6——展示博客(Alpha版本)
  • 原文地址:https://www.cnblogs.com/yefanqiu/p/1577854.html
Copyright © 2011-2022 走看看