繁体   English   中英

如何将字节数组解析为 object?

[英]How to parse a byte array into a object?

我正在读取几年前预定义的二进制数据(通过网络 stream 或文件)。 我目前通过将其读入字节数组来读取这些数据,然后使用System.BitConverter将该数组转换为我需要的字段。 不用说,这是耗时且容易出错的。

我希望我可以使用ISerializable ,但我不知道如何为预定义的结构实现它。

我希望有关如何改进当前策略的指示...

Rozon,我遇到了同样的问题,我正要放弃解决方案,直到我在这里找到了这个问题,并阅读了 Joe 对此的回复。 Joe 提到了 Marshal object 在常规MEMORY和托管 object 之间移动数据......这就是我所做的,对我来说就像魔法一样......如果你还没有弄清楚这一点,我做了什么,以及我是如何让它发挥作用的......(谢谢乔。)......

首先,您必须能够创建结构的托管实例。 这不应该太难,它只是意味着你的结构上有很多额外的属性。

例如,这是一个包含有关服务器的一些信息的数据结构。 当然,字符串大小不准确,因此请确保您的字符串大小是正确的!

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
struct TServerInformation {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
    public string ComputerName;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
    public string HostName;

    [MarshalAs(UnmanagedType.U4)]
    public Int32 IPAddress;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
    public string AdminName;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
    public string WindowsDir;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
    public string Domain;
};

此外,确保您使用正确的字符集,如果它被编译为使用 Unicode,您需要确保字符集反映了这一点。

现在,这是很酷的部分......

要获得结构的 SIZE,(以及你需要保存它的缓冲区的大小),你只需要使用:

byte[] buff = new byte[Marshal.SizeOf(pStruct)];

而且,有了这个,您现在可以做任何事情来获取这些数据,(我假设您已经知道了所有这些......)然后魔术就可以开始了。 我们所做的是分配一块非托管 memory,然后将缓冲区复制到 memory 块中,然后将其复制回我们的结构中,并释放非托管 ZCD69B4957F06CD818D7BF3D61980E2 块。 这可以很容易地放入可以对任何字节 [] 进行操作的扩展 function 中,使您能够调用如下内容:

pStruct = (TServerInformation)buff.FromMemory();

以下代码为我创造了奇迹。 哦,不要忘记在生产代码中放置 try/catch/finally 块...

// Create our Managed Object...
TServerInformation pStruct = new TServerInformation();
// Allocate our block of unmanaged memory...
IntPtr pMem = Marshal.AllocHGlobal(Marshal.SizeOf(pStruct));
// Copy our buff buffer into that new block of memory...
Marshal.Copy(buff, 0, pMem, buff.Length);
// Type-cast that block of memory with the results of the Marshal object's help...
pStruct = (TServerInformation)Marshal.PtrToStructure(pMem, pStruct.GetType());
// Free that block of memory, that is no longer needed now that the data exists in managed form.
Marshal.FreeHGlobal(pMem);

有了它,这避免了使用序列化时包含的所有额外 header 信息,并且。 这是我发现从托管结构中获取准确的“sizeof()”数据的唯一方法,我确信可能还有其他方法可以做到这一点,但到目前为止,这是我发现的最好的方法,大约5天的搜索,黑客,搜索,调试,黑客。 并搜索更多..:)

如果这对您有用,请告诉我...我很想知道它是否也能解决您的问题。

一种方法是围绕字节数组创建MemoryStream ,然后使用BinaryReader 这使您可以非常轻松地解析原始值等。

但是,它确实取决于数据的字节顺序是否合适。 我在MiscUtil中有一个EndianBinaryReader class 如果内置的不合适,它可以为您提供帮助。

Marshal 互操作类和方法(即 PtrToStruct 和 StructToPtr)也可以在这里提供帮助。 请参阅: http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx

希望这有帮助:

  //set your byte data instead of null
        byte[] data = null;

        MemoryStream stream = new MemoryStream();
        stream.Write(data,0,data.Length);

        BinaryFormatter formatter = new BinaryFormatter();

        Type s1 = (Type)formatter.Deserialize(stream);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM