• .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("我是测试数据
    ");
                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() +
                       "
    字符串是:" + _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() +
                       "
    字符串1是:" + _MyString1 +
                       "
    字符串2是:" + _MyString2 + "
    ";
            }
        }

    输出:

    原始对象是:
    整数是: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() +
                    "
    字符串是:" + _MyString + "
    ";
            }
            //实现反序列化
            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 + "
    ";
            }
            //实现反序列化
            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

  • 相关阅读:
    python学习笔记(29)-操作excel
    python学习笔记(28)-unittest单元测试-执行用例
    python学习笔记(27)-unittest单元测试-测试用例
    python学习笔记(26)-request模块
    python学习笔记(25)-继承
    c++ 流基本概念
    友元函数、类和运算符重载
    c++中的引用
    c++重点知识点
    指针和结构体
  • 原文地址:https://www.cnblogs.com/jesselzj/p/4797567.html
Copyright © 2020-2023  润新知