zoukankan      html  css  js  c++  java
  • C# 对象、文件与二进制串(byte数组)之间的转换

    转载地址: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

  • 相关阅读:
    [导入]习惯修改别人的程序吗?
    [导入]感悟一首:"原来你也在这里"
    [导入]人生的高度
    [导入]nslookup工具的使用方法(转)
    [导入]回忆ASP!
    [导入]论坛的修改完成
    [导入]还原精灵安装失败!
    [导入]IE6无提示关闭窗口,不是利用activeX
    加密算法
    澄清VB调用API时字符串参数的困惑
  • 原文地址:https://www.cnblogs.com/Arlar/p/5860188.html
Copyright © 2011-2022 走看看