C#物件、檔案與二進位制串(byte陣列)之間的轉換
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;
1 /// <summary> 2 /// 工具類:物件與二進位制流間的轉換 3 /// </summary> 4 class ByteConvertHelper 5 { 6 /// <summary> 7 /// 將物件轉換為byte陣列 8 /// </summary> 9 /// <param name="obj">被轉換物件</param> 10 /// <returns>轉換後byte陣列</returns> 11 public static byte[] Object2Bytes(objectobj) 12 { 13 byte[] buff; 14 using (MemoryStream ms = new MemoryStream()) 15 { 16 IFormatter iFormatter = new BinaryFormatter(); 17 iFormatter.Serialize(ms, obj); 18 buff = ms.GetBuffer(); 19 } 20 return buff; 21 } 2223 /// <summary> 24 /// 將byte陣列轉換成物件 25 /// </summary> 26 /// <param name="buff">被轉換byte陣列</param> 27 /// <returns>轉換完成後的物件</returns> 28 public static object Bytes2Object(byte[] buff) 29 { 30 object obj; 31 using (MemoryStream ms = new MemoryStream(buff)) 32 { 33 IFormatter iFormatter = new BinaryFormatter(); 34 obj = iFormatter.Deserialize(ms); 35 } 36 return obj; 37 } 38 }
呼叫示例:
假設有一個添加了Serializable特性的結構:
1 /// <summary> 2 /// 測試結構 3 /// </summary> 4 [Serializable] 5 struct TestStructure 6 { 7 public string A; //變數A 8 public char B; //變數B 9 public int C; //變數C 10 11 /// <summary> 12 /// 建構函式 13 /// </summary> 14 /// <param name="paraA"></param> 15 /// <param name="paraB"></param> 16 /// <param name="paraC"></param> 17 public TestStructure(string paraA, char paraB, int paraC) 18 { 19 this.A = paraA; 20 this.B = paraB; 21 this.C = paraC; 22 } 23 24 /// <summary> 25 /// 輸出本結構中內容 26 /// </summary> 27 /// <returns></returns> 28 public string DisplayInfo() 29 { 30 return string.Format("A:{0};B:{1};C:{2}", this.A, this.B, this.C); 31 } 32 }
那麼呼叫下面的程式碼可以完成這個結構的轉換
1 static void Main(string[] args) 2 { 3 TestStructure tsA = new TestStructure("1234", '5', 6); 4 byte[] bytTemp = ByteConvertHelper.Object2Bytes(tsA); 5 Console.WriteLine("陣列長度:" + bytTemp.Length); 6 TestStructure tsB = (TestStructure)ByteConvertHelper.Bytes2Object(bytTemp); 7 Console.WriteLine(tsB.DisplayInfo()); 8 9 Console.ReadLine(); 10 }
輸出為:
需要注意的是,用這個方式進行結構與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
1 /// <summary> 2 /// 工具類:物件與二進位制流間的轉換 3 /// </summary> 4 class ByteConvertHelper 5 { 6 /// <summary> 7 /// 將物件轉換為byte陣列 8 /// </summary> 9 /// <param name="obj">被轉換物件</param> 10 /// <returns>轉換後byte陣列</returns> 11 public static byte[] Object2Bytes(object obj) 12 { 13 byte[] buff = new byte[Marshal.SizeOf(obj)]; 14 IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0); 15 Marshal.StructureToPtr(obj, ptr, true); 16 return buff; 17 } 18 19 /// <summary> 20 /// 將byte陣列轉換成物件 21 /// </summary> 22 /// <param name="buff">被轉換byte陣列</param> 23 /// <param name="typ">轉換成的類名</param> 24 /// <returns>轉換完成後的物件</returns> 25 public static object Bytes2Object(byte[] buff, Type typ) 26 { 27 IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0); 28 return Marshal.PtrToStructure(ptr, typ); 29 } 30 }
呼叫示例:
現有結構如下(就是比上面示例中的結構少了特性Serializable):
1 /// <summary> 2 /// 測試結構 3 /// </summary> 4 struct TestStructure 5 { 6 public string A; //變數A 7 public char B; //變數B 8 public int C; //變數C 9 10 /// <summary> 11 /// 建構函式 12 /// </summary> 13 /// <param name="paraA"></param> 14 /// <param name="paraB"></param> 15 /// <param name="paraC"></param> 16 public TestStructure(string paraA, char paraB, int paraC) 17 { 18 this.A = paraA; 19 this.B = paraB; 20 this.C = paraC; 21 } 22 23 /// <summary> 24 /// 輸出本結構中內容 25 /// </summary> 26 /// <returns></returns> 27 public string DisplayInfo() 28 { 29 return string.Format("A:{0};B:{1};C:{2}", this.A, this.B, this.C); 30 } 31 }
呼叫下面的程式碼可以完成轉換:
1 static void Main(string[] args) 2 { 3 TestStructure tsA = new TestStructure("1234", '5', 6); 4 byte[] bytTemp = ByteConvertHelper.Object2Bytes(tsA); 5 Console.WriteLine("陣列長度:" + bytTemp.Length); 6 TestStructure tsB = (TestStructure)ByteConvertHelper.Bytes2Object( 7 bytTemp, Type.GetType("ByteConverter2.TestStructure")); 8 Console.WriteLine(tsB.DisplayInfo()); 9 10 Console.ReadLine(); 11 }
執行示例:
可以看到,陣列長度僅為12,比上面示例中轉換的byte[]陣列短了非常多,更加節省空間
4.使用FileStream將檔案與byte陣列相互轉換
實現這個功能,需要先引用名稱空間:System.IO
1 /// <summary> 2 /// 工具類:檔案與二進位制流間的轉換 3 /// </summary> 4 class FileBinaryConvertHelper 5 { 6 /// <summary> 7 /// 將檔案轉換為byte陣列 8 /// </summary> 9 /// <param name="path">檔案地址</param> 10 /// <returns>轉換後的byte陣列</returns> 11 public static byte[] File2Bytes(string path) 12 { 13 if(!File.Exists(path)) 14 { 15 return new byte[0]; 16 } 17 18 FileInfo fi = new FileInfo(path); 19 byte[] buff = new byte[fi.Length]; 20 21 FileStream fs = fi.OpenRead(); 22 fs.Read(buff, 0, Convert.ToInt32(fs.Length)); 23 fs.Close(); 24 25 return buff; 26 } 27 28 /// <summary> 29 /// 將byte陣列轉換為檔案並儲存到指定地址 30 /// </summary> 31 /// <param name="buff">byte陣列</param> 32 /// <param name="savepath">儲存地址</param> 33 public static void Bytes2File(byte[] buff, string savepath) 34 { 35 if (File.Exists(savepath)) 36 { 37 File.Delete(savepath); 38 } 39 40 FileStream fs = new FileStream(savepath, FileMode.CreateNew); 41 BinaryWriter bw = new BinaryWriter(fs); 42 bw.Write(buff, 0, buff.Length); 43 bw.Close(); 44 fs.Close(); 45 } 46 }
假設有檔案test.txt,呼叫下面程式碼可以將test.txt寫到byte陣列中,並將這個byte陣列的內容寫入到檔案output.txt裡
1 static void Main(string[] args) 2 { 3 byte[] bytTemp = FileBinaryConvertHelper.File2Bytes("test.txt"); 4 Console.WriteLine("陣列長度:" + bytTemp.Length); 5 FileBinaryConvertHelper.Bytes2File(bytTemp, "output.txt"); 6 Console.WriteLine("輸出完成"); 7 8 Console.ReadLine(); 9 }
執行結果:
END
轉:https://my.oschina.net/Tsybius2014/blog/352409