.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, , bufferlength)) > )
{
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 = ; i < data.LongLength; i += bufferlength)
{
int length = bufferlength;
if (i + bufferlength > data.LongLength)
length = (int)(data.LongLength - i);
Array.Copy(data, i, buffer, , length);
stream.Write(buffer, , length);
}
}
}
    partial class UseStream
{
private const int bufferlength = ; 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 = ; i < ; 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 = ;

        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 = ; i < ; 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, , bufferlength)) > )
{
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 = ; i < data.LongLength; i += bufferlength)
{
int length = bufferlength;
if (i + bufferlength > data.LongLength)
length = (int)(data.LongLength - i);
Array.Copy(data, i, buffer, , length);
stream.Write(buffer, , 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(, "我是字符串");
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(, "我是字符串");
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 = ;
_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(, "我是字符串");
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

上一篇:Mac包管理神器Homebrew


下一篇:MySQL Procedure(MySQL存储过程)[转]