• 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

  • 相关阅读:
    云端: 小软件大平台,绿色又安全 V0.9 Beta3(090722)
    Kindle 中文阅读终极优化指南
    编辑距离
    在IE中输入网址不能访问,但输入IP地址可以访问,为什么?
    英文缩写解释
    为什么有时上网速度很慢?
    常用命令
    如何使用ping命令检查网络故障
    密码的故事
    提示主机名冲突怎么办?
  • 原文地址:https://www.cnblogs.com/X-Jonney/p/13607721.html
Copyright © 2020-2023  润新知