c#中的Struct与Byte[]互转

c#中要让struct转换为byte[],首先要在struct申明中说明struct的结构,如下:

 

代码

    
/// <summary>
    
/// 数据包内容的头信息
    
/// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    
public struct TransHead
    {
        
/// <summary>
        
/// 本结构的字节大小
        
/// </summary>
        public static readonly int Size = Marshal.SizeOf(typeof(TransHead));

        
/// <summary>
        
/// 请求类型
        
/// </summary>
        [MarshalAs(UnmanagedType.I4)]
        
public RequestType Type;
        
/// <summary>
        
/// 请求子类型
        
/// </summary>
        [MarshalAs(UnmanagedType.I4)]
        
public REFRESH SubType;
        
/// <summary>
        
/// 协议版本
        
/// </summary>
        public int Edition;
        
/// <summary>
        
/// 标识(系统返回值)
        
/// </summary>
        public int Flag;
    }
    
/// <summary>
    
/// 数据包内容,头信息加定长数据
    
/// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    
public struct TransHeadAndData
    {
        
/// <summary>
        
/// 本结构的字节大小
        
/// </summary>
        public static readonly int Size = Marshal.SizeOf(typeof(TransHeadAndData));
        
/// <summary>
        
/// 本结构数据体的字节大小(结构大小-结构头)
        
/// </summary>
        public static readonly int SubSize = Size - TransHead.Size;

        [MarshalAs(UnmanagedType.Struct)]
        
public TransHead DataHead;

        
/// <summary>
        
/// 具体数据 x460
        
/// </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 460)]
        
public byte[] Data;
    }
    
public struct TransUplink
    {
        
/// <summary>
        
/// 本结构的字节大小
        
/// </summary>
        public static readonly int Size = Marshal.SizeOf(typeof(TransUplink));// - 4;
        /// <summary>
        
/// 数据类型
        
/// </summary>
        [MarshalAs(UnmanagedType.I4)]
        
public RequestType Type;
        
/// <summary>
        
/// /// 数据内容
        
/// </summary>
        [MarshalAs(UnmanagedType.Struct)]
        
public TransHeadAndData Data;
        
///// <summary>
        
///// 发送上去的数据头长度(仅用户客户端,用于接收数据后删除重发列表时的计算,计算结构大小时不加入该项)
        
///// </summary>
        //public int HeadLenght;
    }

 

 

以下是基本转换方法

 

代码
     /// <summary>
        
/// 将struct类型转换为byte[]
        
/// </summary>
        public static byte[] StructToBytes(object structObj, int size)
        {
            IntPtr buffer 
= Marshal.AllocHGlobal(size);
            
try//struct_bytes转换
            {
                Marshal.StructureToPtr(structObj, buffer, 
false);
                
byte[] bytes = new byte[size];
                Marshal.Copy(buffer, bytes, 
0, size);
                
return bytes;
            }
            
catch (Exception ex)
            {
                
throw new Exception("Error in StructToBytes ! " + ex.Message);
            }
            
finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

 

 

代码
        /// <summary>
        
/// 将byte[]还原为指定的struct,该函数的泛型仅用于自定义结构
        
/// startIndex:数组中 Copy 开始位置的从零开始的索引。
        
/// length:要复制的数组元素的数目。
        
/// </summary>
        public static T BytesToStruct<T>(byte[] bytes, int startIndex, int length)
        {
            
if (bytes == nullreturn default(T);
            
if (bytes.Length <= 0return default(T);
            IntPtr buffer 
= Marshal.AllocHGlobal(length);
            
try//struct_bytes转换
            {
                Marshal.Copy(bytes, startIndex, buffer, length);
                
return (T)Marshal.PtrToStructure(buffer, typeof(T));
            }
            
catch(Exception ex)
            {
                
throw new Exception("Error in BytesToStruct ! " + ex.Message);
            }
            
finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

 

 

犹豫频繁的重复调用 IntPtr buffer = Marshal.AllocHGlobal(size);语句,会出现缓存创建错误的情况(溢出之类的错误)

所以在写入列表型数据时使用下面的优化方法

 

代码

        
/// <summary>
        
/// 将List<struct>类型转换为byte[]并写入流
        
/// </summary>
        public static void SetFromListToStream<T>(List<T> inList, int size, FS.FileStreamEx stream, long offset, int listStart, int listCount)
        {
            IntPtr buffer 
= Marshal.AllocHGlobal(size);
            
try//struct_bytes转换
            {
                
if (listCount < 0) listCount = inList.Count;
                
//若需写入的数据条数太大,则将其分为N块批量写入
                int num = listCount;
                
if (num > 100)
                {
                    num 
= num / 100;
                }
                
else
                {
                    num 
= 1;
                }

                
byte[] numByte = new byte[num * size];
                
byte[] bytes = new byte[size];
                
for (int i = 0; i < listCount; i++)
                {
                    
//批量写入模式
                    if (num > 1 && num + i < listCount)
                    {

                        
for (int j = 0; j < num; j++)
                        {
                            Marshal.StructureToPtr(inList[listStart 
+ i + j], buffer, false);
                            Marshal.Copy(buffer, numByte, j 
* size, size);
                        }
                        stream.WriteBytes(offset 
+ i * size, numByte);
                        i 
+= num - 1;//-1因为外面的for循环中i是+1的
                    }
                    
//逐条写入模式
                    else
                    {
                        Marshal.StructureToPtr(inList[listStart 
+ i], buffer, false);
                        Marshal.Copy(buffer, bytes, 
0, size);
                        stream.WriteBytes(offset 
+ i * size, bytes);
                    }
                }
            }
            
catch(Exception ex)
            {
                
throw new Exception("Error in SetFromListToStream ! " + ex.Message);
            }
            
finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

 

同理,在读出时也应该使用优化方法

 

代码
        public static int SetFromStreamToList<T>(ref List<T> inList, int size, FS.FileStreamEx stream, long offset, int lenght, bool clear)
        {
            
if (clear) inList.Clear();
            
if (offset < 0) offset = 0;
            
if (lenght <= 0) lenght = (int)(stream.Length - offset);
            
byte[] tmpByte = stream.ReadBytes(offset, lenght);
            
if (tmpByte == nullreturn ErrCode.Success;
            
return SetFromBytesToList<T>(ref inList, size, tmpByte, 00);
        }

        
/// <summary>
        
/// 将byte[]内容转为指定结构,并添加到相应的List中,该函数的泛型仅用于自定义结构
        
/// </summary>
        
/// <typeparam name="T">将要转换的类型,同时也是List的类型</typeparam>
        
/// <param name="inList">将要添加数据的List</param>
        
/// <param name="size">指定类型的长度,传入长度是为了避免每次都去计算结构长度</param>
        
/// <param name="inByte">将要转换的数据</param>
        
/// <param name="offset">便宜量,从数组中指定位置开始转换,取值范围:0至lenght</param>
        
/// <param name="lenght">将要转换的数据长度,
        
/// 若lenght大于等于inByte.Lenght则lenght=inByte.Lenght;
        
/// 若lenght小于等于0则lenght=inByte.Lenght</param>
        
/// <param name="clear">添加前是否清除旧数据</param>
        
/// <returns>是否成功</returns>
        public static int SetFromBytesToList<T>(ref List<T> inList, int size, byte[] inByte, long offset, int lenght, bool clear)
        {
            
lock (inList)
            {
                
if (clear) inList.Clear();
                
if (lenght <= 0) lenght = inByte.Length;
                
if (lenght <= 0return ErrCode.Success;

                IntPtr buffer 
= Marshal.AllocHGlobal(size);
                
int i;
                
try//struct_bytes转换
                {
                    
for (i = (int)offset; i + size <= lenght; i += size)
                    {
                        Marshal.Copy(inByte, i, buffer, size);
                        inList.Add((T)Marshal.PtrToStructure(buffer, 
typeof(T)));
                    }
                }
                
catch(Exception ex)
                {
                    
throw new Exception("Error in SetFromBytesToList ! " + ex.Message);
                }
                
finally
                {
                    Marshal.FreeHGlobal(buffer);
                }
                
return ErrCode.Success;
            }
        }

 

 

 

 

 

 

 

 

 

posted @ 2010-07-01 12:16  风叙  阅读(6791)  评论(0)    收藏  举报