轉載地址:http://my.oschina.net/Tsybius2014/blog/352409#navbar-header
1.關於本文
在使用C#下的TCP(類TcpClient)、UDP(類UdpClient)協議傳輸信息時,都需要將信息轉換為byte類型的數組進行發送。本文實現了兩種object與byte數組的轉換和一種文件與byte數組轉換的方式。基礎類型的數據,可以用BitConverter類中的函數進行轉換。
2.object與byte[]的相互轉換:使用IFormatter的Serialize和Deserialize進行序列化與反序列化
實現這個功能,需要先引用三個命名空間:System.IO、System.Runtime.Serialization、System.Runtime.Serialization.Formatters.Binary;
/// <summary> /// 工具類:對象與二進制流間的轉換 /// </summary> class ByteConvertHelper { /// <summary> /// 將對象轉換為byte數組 /// </summary> /// <param name="obj">被轉換對象</param> /// <returns>轉換后byte數組</returns> public static byte[] Object2Bytes(object obj) { byte[] buff; using (MemoryStream ms = new MemoryStream()) { IFormatter iFormatter = new BinaryFormatter(); iFormatter.Serialize(ms, obj); buff = ms.GetBuffer(); } return buff; } /// <summary> /// 將byte數組轉換成對象 /// </summary> /// <param name="buff">被轉換byte數組</param> /// <returns>轉換完成后的對象</returns> public static object Bytes2Object(byte[] buff) { object obj; using (MemoryStream ms = new MemoryStream(buff)) { IFormatter iFormatter = new BinaryFormatter(); obj = iFormatter.Deserialize(ms); } return obj; } }
調用示例:
假設有一個添加了Serializable特性的結構:
/// <summary> /// 測試結構 /// </summary> [Serializable] struct TestStructure { public string A; //變量A public char B; //變量B public int C; //變量C /// <summary> /// 構造函數 /// </summary> /// <param name="paraA"></param> /// <param name="paraB"></param> /// <param name="paraC"></param> public TestStructure(string paraA, char paraB, int paraC) { this.A = paraA; this.B = paraB; this.C = paraC; } /// <summary> /// 輸出本結構中內容 /// </summary> /// <returns></returns> public string DisplayInfo() { return string.Format("A:{0};B:{1};C:{2}", this.A, this.B, this.C); } }
那么調用下面的代碼可以完成這個結構的轉換
static void Main(string[] args) { TestStructure tsA = new TestStructure("1234", '5', 6); byte[] bytTemp = ByteConvertHelper.Object2Bytes(tsA); Console.WriteLine("數組長度:" + bytTemp.Length); TestStructure tsB = (TestStructure)ByteConvertHelper.Bytes2Object(bytTemp); Console.WriteLine(tsB.DisplayInfo()); Console.ReadLine(); }
輸出為:

需要注意的是,用這個方式進行結構與byte數組間的轉換,結構或類必須有Serializable特性。否則會有異常(SerializationException):“程序集 "XXX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 中的類型 "XXX.XXX" 未標記為可序列化”
另外,這個方式生成的byte數組長度較大
3.使用Marshal類的StructureToPtr與PtrToStructure函數對object與byte數組進行轉換
實現這個功能,需要先引用命名空間:System.Runtime.InteropServices
/// <summary> /// 工具類:對象與二進制流間的轉換 /// </summary> class ByteConvertHelper { /// <summary> /// 將對象轉換為byte數組 /// </summary> /// <param name="obj">被轉換對象</param> /// <returns>轉換后byte數組</returns> public static byte[] Object2Bytes(object obj) { byte[] buff = new byte[Marshal.SizeOf(obj)]; IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0); Marshal.StructureToPtr(obj, ptr, true); return buff; } /// <summary> /// 將byte數組轉換成對象 /// </summary> /// <param name="buff">被轉換byte數組</param> /// <param name="typ">轉換成的類名</param> /// <returns>轉換完成后的對象</returns> public static object Bytes2Object(byte[] buff, Type typ) { IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0); return Marshal.PtrToStructure(ptr, typ); } }
調用示例:
現有結構如下(就是比上面示例中的結構少了特性Serializable):
/// <summary> /// 測試結構 /// </summary> struct TestStructure { public string A; //變量A public char B; //變量B public int C; //變量C /// <summary> /// 構造函數 /// </summary> /// <param name="paraA"></param> /// <param name="paraB"></param> /// <param name="paraC"></param> public TestStructure(string paraA, char paraB, int paraC) { this.A = paraA; this.B = paraB; this.C = paraC; } /// <summary> /// 輸出本結構中內容 /// </summary> /// <returns></returns> public string DisplayInfo() { return string.Format("A:{0};B:{1};C:{2}", this.A, this.B, this.C); } }
調用下面的代碼可以完成轉換:
static void Main(string[] args) { TestStructure tsA = new TestStructure("1234", '5', 6); byte[] bytTemp = ByteConvertHelper.Object2Bytes(tsA); Console.WriteLine("數組長度:" + bytTemp.Length); TestStructure tsB = (TestStructure)ByteConvertHelper.Bytes2Object( bytTemp, Type.GetType("ByteConverter2.TestStructure")); Console.WriteLine(tsB.DisplayInfo()); Console.ReadLine(); }
運行示例:

可以看到,數組長度僅為12,比上面示例中轉換的byte[]數組短了非常多,更加節省空間
4.使用FileStream將文件與byte數組相互轉換
實現這個功能,需要先引用命名空間:System.IO
/// <summary> /// 工具類:文件與二進制流間的轉換 /// </summary> class FileBinaryConvertHelper { /// <summary> /// 將文件轉換為byte數組 /// </summary> /// <param name="path">文件地址</param> /// <returns>轉換后的byte數組</returns> public static byte[] File2Bytes(string path) { if(!File.Exists(path)) { return new byte[0]; } FileInfo fi = new FileInfo(path); byte[] buff = new byte[fi.Length]; FileStream fs = fi.OpenRead(); fs.Read(buff, 0, Convert.ToInt32(fs.Length)); fs.Close(); return buff; } /// <summary> /// 將byte數組轉換為文件並保存到指定地址 /// </summary> /// <param name="buff">byte數組</param> /// <param name="savepath">保存地址</param> public static void Bytes2File(byte[] buff, string savepath) { if (File.Exists(savepath)) { File.Delete(savepath); } FileStream fs = new FileStream(savepath, FileMode.CreateNew); BinaryWriter bw = new BinaryWriter(fs); bw.Write(buff, 0, buff.Length); bw.Close(); fs.Close(); } }
假設有文件test.txt,調用下面代碼可以將test.txt寫到byte數組中,並將這個byte數組的內容寫入到文件output.txt里
static void Main(string[] args) { byte[] bytTemp = FileBinaryConvertHelper.File2Bytes("test.txt"); Console.WriteLine("數組長度:" + bytTemp.Length); FileBinaryConvertHelper.Bytes2File(bytTemp, "output.txt"); Console.WriteLine("輸出完成"); Console.ReadLine(); }
運行結果:

END
