1. 程式人生 > 實用技巧 >C#物件、檔案與二進位制串(byte陣列)之間的轉換

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(object
obj) 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 } 22
23 /// <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