.NET基础 (10)流和序列化
流和序列化
1 什么是流,.NET中有哪些常见的流
2 如何使用压缩流
3 Serializable特性有何作用
4 .NET提供了哪几种可进行序列化操作的类型
5 如何自定义序列化和反序列化的过程
流是对字节集合对象的一种操作。.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方法被调用。
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
字符串是:
.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
字符串是:我是字符串
子类字符串是:我是字符串
转载请注明出处: