.NET基础 (10)流和序列化

流和序列化
1 什么是流,.NET中有哪些常见的流
2 如何使用压缩流
3 Serializable特性有何作用
4 .NET提供了哪几种可进行序列化操作的类型
5 如何自定义序列化和反序列化的过程

 

流和序列化
1 什么是流,.NET中有哪些常见的流

流是对字节集合对象的一种操作。.NET中常见的流类型有FileStream、NetworkStream、UnmanagedMemoryStream、MemoryStream等。

流的示例:

    partial class UseStream
    {
        //从一个流总读取所有字节
        static Byte[] ReadAllBytes(Stream stream, int bufferlength)
        {
            Byte[] buffer = new Byte[bufferlength];
            List<Byte> result = new List<Byte>();
            int read;
            while ((read = stream.Read(buffer, 0, bufferlength)) > 0)
            {
                if (read < bufferlength)
                {
                    Byte[] temp = new Byte[read];
                    Array.Copy(buffer, temp, read);
                    result.AddRange(temp);
                }
                else
                    result.AddRange(buffer);
            }
            return result.ToArray();
        }
        //把字节写入一个流中
        static void WriteAllBytes(Stream stream, Byte[] data, int bufferlength)
        {
            Byte[] buffer = new Byte[bufferlength];
            for (long i = 0; i < data.LongLength; i += bufferlength)
            {
                int length = bufferlength;
                if (i + bufferlength > data.LongLength)
                    length = (int)(data.LongLength - i);
                Array.Copy(data, i, buffer, 0, length);
                stream.Write(buffer, 0, length);
            }
        }
    }

 

    partial class UseStream
    {
        private const int bufferlength = 1024;

        static void Main(string[] args)
        {
            //创建一个文件,并写入内容
            String filename = "C:\\TestStream.txt";
            String filecontent = GetTestString();
            try
            {
                //创建文件并写入内容
                using (FileStream fs =
                    new FileStream(filename, FileMode.Create))
                {
                    Byte[] bytes = Encoding.Default.GetBytes(filecontent);
                    WriteAllBytes(fs, bytes, bufferlength);
                    fs.Close();
                }

                //读取文件并且打印出来
                using (FileStream fr =
                    new FileStream(filename, FileMode.Open))
                {
                    Byte[] result = ReadAllBytes(fr, bufferlength);
                    Console.WriteLine(Encoding.Default.GetString(result));
                    fr.Close();
                }
            }
            finally
            {
                //清除测试文件
                try
                {
                    if (File.Exists(filename))
                        File.Delete(filename);
                }
                finally { }
                Console.Read();
            }
        }
        //取得测试数据
        static String GetTestString()
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < 10; i++)
                builder.Append("我是测试数据\r\n");
            return builder.ToString();
        }

    }

 

所有常见的流类型都继承自System.IO.Stream。Stream类型实现了IDisposable接口,所有的流类型都应该使用using语句确保Dispose方法被调用。


2 如何使用压缩流

System.IO.Compression下定义了两个用于压缩数据的类型:DeflateStream和GZioStream,两者都继承自System.IO.Stream。在.NET4之前,这两类的压缩算法并不出色,并且不支持调整压缩率。有些第三方组件如SharpZipLib实现了更高效的压缩解压算法。在.NET4中,对它们做了改善,提供了更好的压缩算法。

示例:

        private const int bufferlength = 1024;

        static void Main(string[] args)
        {
            String test = GetTestString();
            Byte[] original = Encoding.Default.GetBytes(test);
            Console.WriteLine("数据的原始长度是:" +
                original.LongLength.ToString());
            //进行压缩
            Byte[] compressed = Compress(original);
            Console.WriteLine("压缩后的数据长度是:" +
                compressed.LongLength);
            //进行解压
            Byte[] back = DeCompress(compressed);
            Console.WriteLine("解压后得到数据长度:" +
                back.LongLength.ToString());
            Console.WriteLine("解压前后是否相等:"+
                test.Equals(Encoding.Default.GetString(back)));
            Console.Read();
        }

        //压缩数据
        static Byte[] Compress(Byte[] data)
        {
            //压缩入这个内存流
            using (MemoryStream target = new MemoryStream())
            {
                using (GZipStream gs =
                    new GZipStream
                    (target,CompressionMode.Compress,true))
                {
                    WriteAllBytes(gs, data, bufferlength);
                }
                return target.ToArray();
            }
        }
        //解压数据
        static Byte[] DeCompress(Byte[] data)
        {
            using (MemoryStream source = new MemoryStream(data))
            {
                using (GZipStream gs =
                    new GZipStream
                    (source, CompressionMode.Decompress, true))
                {
                    return ReadAllBytes(gs, bufferlength);
                }
            }
        }
        //准备测试数据
        static String GetTestString()
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < 1000; i++)
                builder.Append("我是测试数据");
            return builder.ToString();
        }
        //从一个流总读取所有字节
        static Byte[] ReadAllBytes(Stream stream, int bufferlength)
        {
            Byte[] buffer = new Byte[bufferlength];
            List<Byte> result = new List<Byte>();
            int read;
            while ((read = stream.Read(buffer, 0, bufferlength)) > 0)
            {
                if (read < bufferlength)
                {
                    Byte[] temp = new Byte[read];
                    Array.Copy(buffer, temp, read);
                    result.AddRange(temp);
                }
                else
                    result.AddRange(buffer);
            }
            return result.ToArray();
        }
        //把字节写入一个流中
        static void WriteAllBytes(Stream stream, Byte[] data, int bufferlength)
        {
            Byte[] buffer = new Byte[bufferlength];
            for (long i = 0; i < data.LongLength; i += bufferlength)
            {
                int length = bufferlength;
                if (i + bufferlength > data.LongLength)
                    length = (int)(data.LongLength - i);
                Array.Copy(data, i, buffer, 0, length);
                stream.Write(buffer, 0, length);
            }
        }

 

输出:

数据的原始长度是:12000
压缩后的数据长度是:77  //77是.NET4之后的结果。.NET3.5的结果是 274
解压后得到数据长度:12000
解压前后是否相等:True

3 Serializable特性有何作用

对象实例的序列化,是指把实例对象转换为可方便存储、传输和交互的流。而对象的实例则包含类型的成员变量、类型的名称以及对象所在的程序集等信息。

通过为类型添加Serializable特性,可以使对象申明为可被序列化,即可被诸如BinaryFormatter等实现了IFormatter接口的类型的对象序列化和返序列化。

当一个基类使用了Serializable特性之后,并不意味着其所有子类都能被序列化,必须为每个子类都添加Serializable特性来保证其被正确地序列化。

示例:

    class UserSerializable
    {
        static void Main(string[] args)
        {
            MyObject obj = new MyObject(10, "我是字符串");
            Console.WriteLine("初始状态:");
            Console.WriteLine(obj);

            Byte[] data = Serialize(obj);
            MyObject newobj = DeSerialize(data);
            Console.WriteLine("经过序列化和反序列化后:");
            Console.WriteLine(newobj);
            Console.Read();
        }

        //序列化对象
        static Byte[] Serialize(MyObject obj)
        {
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, obj);
                return ms.ToArray();
            }
        }
        //反序列化对象
        static MyObject DeSerialize(Byte[] data)
        {
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(data))
            {
                return (MyObject)formatter.Deserialize(ms);
            }
        }
    }
    //一个可序列化的类型
    [Serializable]
    public class MyObject
    {
        private int _myInt;
        [NonSerialized]
        //这个成员不可被序列化
        private String _myPrivate;
        public MyObject(int i, String s)
        {
            _myInt = i;
            _myPrivate = s;
        }
        public override string ToString()
        {
            return "整数是:" + _myInt.ToString() +
                   "\r\n字符串是:" + _myPrivate;
        }
    }

 

输出:

初始状态:
整数是:10
字符串是:我是字符串
经过序列化和反序列化后:
整数是:10
字符串是:


4 .NET提供了哪几种可进行序列化操作的类型

.NET内建了3个可执行序列化的和反序列化的类型:BinaryFormatter、SoapFormatter、XmlSerializer。

BinaryFormatter和SoapFormatter可以对那些有Serializable特性的类型进行序列化和反序列化操作,除了有NonSerialized特性修饰的成员,两者将序列化所有其他成员。而XmlSerializer不需要对象申明了XmlSerializable特性,但它要求对象类型有一个显示的无参公共构造方法,并且它不能序列化对象的非公共成员和由XmlIgnore修饰的成员。

示例:

    partial class DoSerialize
    {
        static void Main(string[] args)
        {
            MyObject obj = new MyObject(10, "我是字符串");
            Console.WriteLine("原始对象是:");
            Console.WriteLine(obj.ToString());

            //使用 SoapFormatter进行序列化
            Byte[] data = SoapFormatterSerialize(obj);
            Console.WriteLine("SoapFormatter序列化后:");
            Console.WriteLine(Encoding.UTF8.GetString(data));

            //使用XmlSerializer进行序列化
            Byte[] data1 = XmlSerializerSerialize(obj);
            Console.WriteLine("XmlSerializer序列化后:");
            Console.WriteLine(Encoding.UTF8.GetString(data1));
            Console.Read();
        }
    }
    partial class DoSerialize
    {
        /// <summary>
        /// Soap序列化
        /// </summary>
        static Byte[] SoapFormatterSerialize(MyObject obj)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                SoapFormatter sf = new SoapFormatter();
                sf.Serialize(ms, obj);
                return ms.ToArray();
            }
        }
        /// <summary>
        /// Soap反序列化
        /// </summary>
        static MyObject SoapFormatterDeserialize(Byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                SoapFormatter sf = new SoapFormatter();
                return (MyObject)sf.Deserialize(ms);
            }
        }
        /// <summary>
        /// 使用XmlSerilizer序列化
        /// </summary>
        static Byte[] XmlSerializerSerialize(MyObject obj)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                XmlSerializer xs = new XmlSerializer(typeof(MyObject));
                xs.Serialize(ms, obj);
                return ms.ToArray();
            }
        }
        /// <summary>
        /// 使用XmlSerilizer反序列化
        /// </summary>
        static MyObject XmlSerializerDeserialize(Byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                XmlSerializer xs = new XmlSerializer(typeof(MyObject));
                return (MyObject)xs.Deserialize(ms);
            }
        }
    }
    [Serializable]
    public class MyObject
    {
        //私有成员,不能被XmlSerializer序列化
        private int _myInt;
        //申明不可被序列化
        [NonSerialized]
        public String _MyString1;
        //申明不可被XmlSerializer序列化
        [XmlIgnore]
        public String _MyString2;
        public MyObject()
        {
            _myInt = 0;
            _MyString1 = "";
            _MyString2 = "";
        }
        public MyObject(int i, String s)
        {
            _myInt = i;
            _MyString1 = s;
            _MyString2 = s;
        }
        public override string ToString()
        {
            return "整数是:" + _myInt.ToString() +
                   "\r\n字符串1是:" + _MyString1 +
                   "\r\n字符串2是:" + _MyString2 + "\r\n";
        }
    }

 

输出:

原始对象是:
整数是:10
字符串1是:我是字符串
字符串2是:我是字符串

SoapFormatter序列化后:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:MyObject id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MyTest/MyTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<_myInt>10</_myInt>
<_MyString2 id="ref-3">我是字符串</_MyString2>
</a1:MyObject>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

XmlSerializer序列化后:
<?xml version="1.0"?>
<MyObject xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <_MyString1>我是字符串</_MyString1>
</MyObject>

5 如何自定义序列化和反序列化的过程

通过实现ISerializable接口中的GetObjectData方法可以实现自定义的序列化,通过添加带有SerializationInfo和StreamingContext参数的构造方法可以自定义反序列化的过程。

示例:

    class CustomizeSerialization
    {
        static void Main(string[] args)
        {
            MyObjectSon obj = new MyObjectSon(10, "我是字符串");
            Console.WriteLine("初始对象:");
            Console.WriteLine(obj);
            Byte[] data = Serialize(obj);
            Console.WriteLine("经过序列化和反序列化后:");
            Console.WriteLine(DeSerialize(data));
            Console.Read();
        }
        //序列化对象
        static Byte[] Serialize(MyObjectSon obj)
        {
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, obj);
                return ms.ToArray();
            }
        }
        //反序列化对象
        static MyObjectSon DeSerialize(Byte[] data)
        {
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(data))
            {
                return (MyObjectSon)formatter.Deserialize(ms);
            }
        }

    }

    [Serializable]
    class MyObject : ISerializable
    {
        private int _MyInt;
        [NonSerialized]
        private String _MyString;

        public MyObject(int i, String s)
        {
            _MyInt = i;
            _MyString = s;
        }
        public override string ToString()
        {
            return "整数是:" + _MyInt.ToString() +
                "\r\n字符串是:" + _MyString + "\r\n";
        }
        //实现反序列化
        protected MyObject(SerializationInfo info,
            StreamingContext context)
        {
            _MyInt = info.GetInt32("MyObjectInt");
            _MyString = info.GetString("MyObjectString");
        }
        //实现序列化
        public virtual void GetObjectData
            (SerializationInfo info, StreamingContext context)
        {
            info.AddValue("MyObjectInt", _MyInt);
            info.AddValue("MyObjectString", _MyString);
        }
    }
    [Serializable]
    class MyObjectSon : MyObject
    {
        private String _SonString;

        public MyObjectSon(int i, String s)
            : base(i, s)
        {
            _SonString = s;
        }
        public override string ToString()
        {
            return base.ToString() + "子类字符串是:" +
                _SonString + "\r\n";
        }
        //实现反序列化
        protected MyObjectSon(SerializationInfo info,
            StreamingContext context)
            : base(info, context)
        {
            _SonString = info.GetString("MyObjectSonString");
        }
        //实现序列化
        public override void GetObjectData(SerializationInfo info,
            StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("MyObjectSonString", _SonString);
        }
    }

输出:

初始对象:
整数是:10
字符串是:我是字符串
子类字符串是:我是字符串

经过序列化和反序列化后:
整数是:10
字符串是:我是字符串
子类字符串是:我是字符串

转载请注明出处:

作者:JesseLZJ
出处:http://jesselzj.cnblogs.com

posted @ 2015-09-10 13:18  JesseLZJ  阅读(416)  评论(0编辑  收藏  举报