8,协议序列化组件NewLife.Serialization
<?xml:namespace prefix = o />
在開發(fā)某些需要跟第三方平臺(tái)交互的項(xiàng)目時(shí),往往需要解析或者構(gòu)造符合對(duì)方協(xié)議要求的數(shù)據(jù)格式,該操作在.Net中有個(gè)很漂亮的名字——序列化!
在實(shí)際使用中,XML序列化用得比較多,二進(jìn)制序列化也不錯(cuò),只是可控性很低。當(dāng)然,對(duì)于要序列化指定協(xié)議的格式而言,它們就幾乎幫不上忙了。于是有了“協(xié)議序列化組件NewLife.Serialization”。
?
協(xié)議序列化類ProtocolFormatter的主旨是實(shí)現(xiàn)二進(jìn)制格式數(shù)據(jù)和.Net實(shí)體數(shù)據(jù)之間的靈活轉(zhuǎn)換!
?
使用上非常簡(jiǎn)單,下面通過實(shí)現(xiàn)一個(gè)簡(jiǎn)單的消息類來反序列化手機(jī)QQ2008(Mobile)的聊天記錄。
新建一個(gè)控制臺(tái)項(xiàng)目,引用NewLife.Serialization.dll。加入下面的代碼:
FileStream stream = new FileStream("10000.rec", FileMode.Open); ProtocolFormatter formatter = new ProtocolFormatter(typeof(Message)); formatter.Head.Config.NoHead = true; while (stream.Position < stream.Length) {try{Message msg = new Message();formatter.Deserialize(stream, msg);Console.WriteLine("{0}({1}) {2} {3}", msg.Name, msg.Number, msg.Time, msg.MsgKind);Console.WriteLine(msg.Content);if (BitConverter.ToString(msg.Data) != "00-00-00-00-00")Console.WriteLine("未知數(shù)據(jù):{0}", BitConverter.ToString(msg.Data));Console.WriteLine();}catch (EndOfStreamException) { break; } } stream.Close();
第一步實(shí)例化一個(gè)ProtocolFormatter對(duì)象,這里指定了類型為Message;
第二步實(shí)例化一個(gè)Message對(duì)象,這點(diǎn)跟許多組件的反序列化不同,因?yàn)橛袝r(shí)候外部已經(jīng)準(zhǔn)備好了一個(gè)對(duì)象,反序列化只需要填充就可以了;
第三步就是序列化,這里傳入第二步實(shí)例化的對(duì)象。如果這里傳入對(duì)象,第一步實(shí)例化ProtocolFormatter的時(shí)候,就可以不用指定類型了;這里也可以不傳入對(duì)象,Deserialize方法內(nèi)部會(huì)實(shí)例化一個(gè)返回。
下面我們看看Message類:
[ProtocolSerialProperty] public class Message : IProtocolSerializable {#region 屬性private Int16 _Length;/// <summary>消息長(zhǎng)度</summary>public Int16 Length{get { return _Length; }set { _Length = value; }}private String _Content;/// <summary>內(nèi)容</summary>public String Content{get { return _Content; }set { _Content = value; }}private Int32 _Number;/// <summary>號(hào)碼</summary>public Int32 Number{get { return _Number; }set { _Number = value; }}private String _Name;/// <summary>名稱</summary>public String Name{get { return _Name; }set { _Name = value; }}private DateTime _Time;/// <summary>時(shí)間</summary>public DateTime Time{get { return _Time; }set { _Time = value; }}private Int16 _Unknown;/// <summary>未知</summary>public Int16 Unknown{get { return _Unknown; }set { _Unknown = value; }}private MsgKinds _MsgKind;/// <summary>消息類型</summary>public MsgKinds MsgKind{get { return _MsgKind; }set { _MsgKind = value; }}private Byte[] _Data;/// <summary>未知數(shù)據(jù)</summary>public Byte[] Data{get { return _Data; }set { _Data = value; }}#endregion#region 方法const Char tag = (Char)20;static String FixContent(String content){content = content.Replace(tag + "A", "[/驚訝]");content = content.Replace(tag + "N", "[/呲牙]");content = content.Replace(tag + "M", "[/調(diào)皮]");content = content.Replace(tag + "x", "[/驚恐]");content = content.Replace(tag + "J", "[/大哭]");content = content.Replace(tag + "s", "[/難過]");content = content.Replace(tag + "e", "[/愛心]");content = content.Replace(tag + "o", "[/強(qiáng)]");content = content.Replace(tag + "K", "[/尷尬]");content = content.Replace(tag + "C", "[/色]");content = content.Replace(tag + "\\", "[/飽]");content = content.Replace(tag + "E", "[/得意]");content = content.Replace(tag + "b", "[/玫瑰]");content = content.Replace(tag + "v", "[/抓狂]");content = content.Replace(tag.ToString() + (Char)139, "[/可愛]");content = content.Replace(tag.ToString() + (Char)153, "[/再見]");content = content.Replace(tag.ToString() + (Char)138, "[/偷笑]");content = content.Replace(tag.ToString() + (Char)121, "[/流汗]");content = content.Replace(tag.ToString() + (Char)162, "[/擦汗]");content = content.Replace(tag.ToString() + (Char)171, "[/委屈]");content = content.Replace(tag.ToString() + (Char)141, "[/傲慢]");content = content.Replace(tag.ToString() + (Char)197, "[/獻(xiàn)吻]");content = content.Replace(tag.ToString() + (Char)146, "[/疑問]");content = content.Replace(tag.ToString() + (Char)166, "[/壞笑]");content = content.Replace(tag.ToString() + (Char)149, "[/折磨]");content = content.Replace(tag.ToString() + (Char)168, "[/右哼哼]");content = content.Replace(tag.ToString() + (Char)170, "[/鄙視]");content = content.Replace(tag.ToString() + (Char)172, "[/快哭了]");content = content.Replace(tag.ToString() + (Char)181, "[/示愛]");content = content.Replace(tag.ToString() + (Char)140, "[/白眼]");content = content.Replace(tag.ToString() + (Char)174, "[/愛情]");content = content.Replace(tag.ToString() + (Char)182, "[/瓢蟲]");content = content.Replace(tag.ToString() + (Char)161, "[/冷汗]");//if (content.Contains(tag.ToString())) throw new Exception("未識(shí)別!");return content;}#endregion#region IProtocolSerializable 成員object IProtocolSerializable.OnCreateInstance(ReadContext context, Type type){return null;}void IProtocolSerializable.OnDeserialized(ReadContext context){}bool IProtocolSerializable.OnDeserializing(ReadContext context){BinaryReader reader = context.Reader;if (context.Node.Name == "Content"){context.Data = ReadString(context.Reader);return false;}else if (context.Node.Name == "Name"){context.Data = ReadString2(context.Reader);return false;}else if (context.Node.Name == "Time"){Int32[] ds = new Int32[7];Int32 m = 0;for (int i = 0; i < ds.Length; i++){ds[i] = reader.ReadInt16();}DateTime dt = new DateTime(ds[0], ds[1], ds[3], ds[4], ds[5], ds[2], DateTimeKind.Utc);context.Data = dt.ToLocalTime();return false;}else if (context.Node.Name == "Data"){context.Data = context.Reader.ReadBytes(5);return false;}return true;}static String ReadString(BinaryReader reader){Int32 msglen = reader.ReadInt16();if (reader.BaseStream.Position > 4) msglen = reader.ReadInt16();Byte[] buffer = reader.ReadBytes(msglen);String str = Encoding.Unicode.GetString(buffer);str = FixContent(str);return str;}static String ReadString2(BinaryReader reader){Int32 msglen = reader.ReadInt16();Byte[] buffer = reader.ReadBytes(msglen * 2);String str = Encoding.Unicode.GetString(buffer);str = FixContent(str);return str;}void IProtocolSerializable.OnSerialized(WriteContext context){}bool IProtocolSerializable.OnSerializing(WriteContext context){return true;}#endregion }public enum MsgKinds : short{系統(tǒng)消息 = 0x110,帶鏈接系統(tǒng)消息 = 0x116,新郵件 = 0x117,請(qǐng)求加好友 = 0x122,通過加好友請(qǐng)求 = 0x0123}Message類主要包含三大部分:
第一是屬性,這點(diǎn)從分析手機(jī)QQ2008聊天記錄文件的格式可以得出。我是一邊試一遍猜,猜出來的;
第二是重點(diǎn)。這個(gè)類實(shí)現(xiàn)了IProtocolSerializable接口,通過OnDeserializing來改變反序列化的行為,某些屬性需要特殊處理的,就在這里處理。
第三部分是處理聊天記錄里面的表情,這個(gè)可有可無。
Message類上面有個(gè)ProtocolSerialProperty特性,指定反序列化的時(shí)候,分析屬性,而不是默認(rèn)的分析字段。這里指定分析屬性,只是為了方便下面寫代碼判別名稱。
執(zhí)行效果如下:
?
協(xié)議序列化組件完全通過反射實(shí)現(xiàn),層層深入,所以性能非常差!我們主要用來序列化BT種子以及各種用于網(wǎng)絡(luò)傳輸?shù)闹噶?#xff0c;因?yàn)橹噶顚?duì)象簡(jiǎn)單,性能上還可以接受。
?
大石頭
新生命開發(fā)團(tuán)隊(duì)
2010-09-29 10758
?
組件示例下載
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的8,协议序列化组件NewLife.Serialization的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《BREW进阶与精通——3G移动增值业务
- 下一篇: 利用 C++ Interop 封装 IS