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