如何在C#中将结构转换为字节数组?
我已经定义了这样的结构:
public struct CIFSPacket
{
public uint protocolIdentifier; //The value must be "0xFF+'SMB'".
public byte command;
public byte errorClass;
public byte reserved;
public ushort error;
public byte flags;
//Here there are 14 bytes of data which is used differently among different dialects.
//I do want the flags2. However, so I'll try parsing them.
public ushort flags2;
public ushort treeId;
public ushort processId;
public ushort userId;
public ushort multiplexId;
//Trans request
public byte wordCount;//Count of parameter words defining the data portion of the packet.
//From here it might be undefined...
public int parametersStartIndex;
public ushort byteCount; //Buffer length
public int bufferStartIndex;
public string Buffer;
}
在我的main方法中,我创建了一个实例并为其赋值:
CIFSPacket packet = new CIFSPacket();
packet.protocolIdentifier = 0xff;
packet.command = (byte)CommandTypes.SMB_COM_NEGOTIATE;
packet.errorClass = 0xff;
packet.error = 0;
packet.flags = 0x00;
packet.flags2 = 0x0001;
packet.multiplexId = 22;
packet.wordCount = 0;
packet.byteCount = 119;
packet.Buffer = "NT LM 0.12";
现在我想通过套接字发送这个数据包 . 为此,我需要将结构转换为字节数组 . 我该怎么做?
我的完整代码如下 .
static void Main(string[] args)
{
Socket MyPing = new Socket(AddressFamily.InterNetwork,
SocketType.Stream , ProtocolType.Unspecified ) ;
MyPing.Connect("172.24.18.240", 139);
//Fake an IP Address so I can send with SendTo
IPAddress IP = new IPAddress(new byte[] { 172,24,18,240 });
IPEndPoint IPEP = new IPEndPoint(IP, 139);
//Local IP for Receiving
IPEndPoint Local = new IPEndPoint(IPAddress.Any, 0);
EndPoint EP = (EndPoint)Local;
CIFSPacket packet = new CIFSPacket();
packet.protocolIdentifier = 0xff;
packet.command = (byte)CommandTypes.SMB_COM_NEGOTIATE;
packet.errorClass = 0xff;
packet.error = 0;
packet.flags = 0x00;
packet.flags2 = 0x0001;
packet.multiplexId = 22;
packet.wordCount = 0;
packet.byteCount = 119;
packet.Buffer = "NT LM 0.12";
MyPing.SendTo(It takes byte array as parameter);
}
代码片段是什么?
13 回答
这很容易,使用编组 .
Top of file
Function
并将其转换回来:
在您的结构中,您需要将它放在字符串之前
并确保SizeConst与您最大的字符串一样大 .
你应该读这个:http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx
如果你真的希望它是快速的,你可以使用CopyMemory使用不安全的代码 . CopyMemory的速度提高了约5倍(例如800MB的数据通过编组复制需要3秒,而只需要通过CopyMemory复制.6s) . 此方法确实限制您仅使用实际存储在struct blob本身中的数据,例如数字或固定长度的字节数组 .
看看这些方法:
这是我在谷歌上发现的另一个线程的无耻副本!
Update :有关详细信息,请查看source
使用较少内存分配的Vicent代码的变体:
我使用
GCHandle
到"pin"内存,然后直接使用h.AddrOfPinnedObject()
的地址 .由于主要答案是使用CIF中没有(或不再)可用的CIFSPacket类型,我编写了正确的方法:
经过测试,他们的工作 .
你可以使用Marshal(StructureToPtr,ptrToStructure)和Marshal.copy,但这是依赖于plataform的 .
序列化包括自定义序列化的功能 .
SerializationInfo包括序列化每个成员的函数 .
BinaryWriter和BinaryReader还包含保存/加载到字节数组(流)的方法 .
请注意,您可以从字节数组创建MemoryStream或从MemoryStream创建字节数组 .
您可以在结构上创建方法Save和方法New:
然后选择要保存/加载到流的成员 - >字节数组 .
这可以非常直接地完成 .
使用
[StructLayout(LayoutKind.Explicit)]
显式定义结构此代码只能在不安全的上下文中编写 . 当你完成它时,你必须释放
addr
.我想出了一种可以转换 any
struct
的不同方法,而无需修复长度的麻烦,但是生成的字节数组会有更多的开销 .这是一个示例
struct
:如您所见,所有这些结构都需要添加固定长度属性 . 这通常会占用比所需更多的空间 . 请注意,
LayoutKind.Sequential
是必需的,因为我们希望反射总是在拉动FieldInfo
时为我们提供相同的顺序 . 我的灵感来自TLV
Type-Length-Value . 我们来看看代码:上面的函数只是使用
BinaryFormatter
来序列化未知大小的原始object
,我只是跟踪大小并将其存储在输出MemoryStream
中 .当我们想要将它转换回原来的
struct
时,我们只需将长度读回并直接将其转储回BinaryFormatter
,然后将其转回struct
.这两个函数是通用的,应该适用于任何
struct
,我已经在我的C#
项目中测试了上面的代码,我有一个服务器和一个客户端,连接并通过NamedPipeStream
进行通信,我将struct
作为字节数组从一个转发到另一个并将它转换回来 .我相信我的方法可能会更好,因为它不会修复
struct
本身的长度,并且对于结构中的每个字段,唯一的开销只是int
. 在BinaryFormatter
生成的字节数组中也有一些微小的开销,但除此之外,并不多 .我将看看BinaryReader和BinaryWriter类 . 我最近不得不将数据序列化为字节数组(并返回),并且在我基本上自己重写之后才发现这些类 .
http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx
该页面上也有一个很好的例子 .
看起来像某个外部库的预定义(C级)结构 . 元帅是你的朋友 . 校验:
http://geekswithblogs.net/taylorrich/archive/2006/08/21/88665.aspx
对于首发如何处理有了这个 . 请注意,您可以 - 使用属性 - 定义字节布局和字符串处理等内容 . 实际上,非常好的方法 .
BinaryFormatter Nor MemoryStream都没有为此完成 .
@Abdel Olakara回答在.net 3.5中不起作用,应修改如下:
这应该很快就能解决问题吧?
此示例仅适用于纯blittable类型,例如,可以直接在C中记忆的类型 .
示例 - 众所周知的64位结构
定义与此完全相同,结构将自动打包为64位 .
现在我们可以创建体素的体积:
并将它们全部保存为字节数组:
但是,由于OP想要知道如何转换结构本身,我们的Voxel结构可以有以下方法
ToBytes
: