装载二进制数据转换成一个结构 [英] loading binary data into a structure

查看:106
本文介绍了装载二进制数据转换成一个结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图来一补结构(不必是一个实际的结构),从一个byte []加载的数据。

I'm trying to fill a structure (does not have to be an actual struct), with data loaded from a byte[].

有许多不同在字节[]数据结构,其中之一是一个字符串,它被声明为:

There are many different data structures in the byte[], one of them is a string, which is declared as:

UInt16 stringLenght
byte[stringLenght] zeroTerminatedString

我的C语言,这可以通过声明一个固定大小的结构处理,以及,而不是包含实际字符串结构,做一个字符串指针

I 'c' language this could be handled by declaring a fixed size struct, and instead of a the struct containing the actual string, make a pointer to the string.

是这样的:

UInt16 stringLength
char* zeroTerminatedString

有一(SMART)的方式做在C#中类似的东西?我的意思是从文件/内存加载的二进制数据,并将其填充到一个结构?

Is there a (smart) way to do something similar in c#? I mean loading binary data from a file/memory and filling it into a structure?

问候
雅各布Justesen

Regards Jakob Justesen

推荐答案

这不是如果文件中的记录包含一个字符串,你会怎样声明它C.那么你声明的结构相似:

That's not how you'd declare it in C. If the record in the file contains a string then you'd declare the structure similar to:

struct Example {
    int mumble;   // Anything, not necessarily a string length
    char text[42];
    // etc...
};



等价的C#的声明看起来像:

The equivalent C# declaration would look like:

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    private struct Example {
        public int mumble;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
        public string text;
        // etc...
    }

您会正常使用BinaryReader读取数据。但它不能直接处理这样的字符串,你要读他们作为一个byte [],做串转换自己。您也可以不走声明语法的优势,你必须写为结构的每个成员的电话。

You'd normally use BinaryReader to read the data. But it cannot handle strings like this directly, you have to read them as a byte[] and do the string conversion yourself. You also cannot take advantage of the declarative syntax, you have to write a call for each individual member of the struct.

有对一个解决办法,Marshal类已经知道如何将非托管的结构转换为管理那些与PtrToStructure()方法。这里有一个通用的实现,它可以用于任何类型的blittable。两个版本,一个静态的,从一个byte [],并且进行了优化,从流反复读一个实例方法读取。你会使用一个FileStream或使用的MemoryStream一个

There's a workaround for that, the Marshal class already knows how to convert unmanaged structures to managed ones with the PtrToStructure() method. Here's a generic implementation, it works for any blittable type. Two versions, a static one that reads from a byte[] and an instance method that was optimized to repeatedly read from a stream. You'd use a FileStream or MemoryStream with that one.

using System;
using System.IO;
using System.Runtime.InteropServices;

class StructTranslator {
    public static bool Read<T>(byte[] buffer, int index, ref T retval) {
        if (index == buffer.Length) return false;
        int size = Marshal.SizeOf(typeof(T));
        if (index + size > buffer.Length) throw new IndexOutOfRangeException();
        var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try {
            IntPtr addr = (IntPtr)((long)handle.AddrOfPinnedObject() + index);
            retval = (T)Marshal.PtrToStructure(addr, typeof(T));
        }
        finally {
            handle.Free();
        }
        return true;
    }

    public bool Read<T>(Stream stream, ref T retval) {
        int size = Marshal.SizeOf(typeof(T));
        if (buffer == null || size > buffer.Length) buffer = new byte[size];
        int len = stream.Read(buffer, 0, size);
        if (len == 0) return false;
        if (len != size) throw new EndOfStreamException();
        var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try {
            retval = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        }
        finally {
            handle.Free();
        }
        return true;
    }

    private byte[] buffer;
}



未经检验的,希望它的作品。

Untested, hope it works.

这篇关于装载二进制数据转换成一个结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆