简体   繁体   English

C#,从二进制文件中读取结构

[英]C#, read structures from binary file

I want to read structures from binary. 我想从二进制文件中读取结构。 In C++ I would do it like this: 在C ++中,我会这样做:

stream.read((char*)&someStruct, sizeof(someStruct));

Is there a similar way in C#? 在C#中是否有类似的方式? The BinaryReader only works for built-in types. BinaryReader仅适用于内置类型。 In .NET 4 there is a MemoryMappedViewAccessor. 在.NET 4中有一个MemoryMappedViewAccessor。 It provides methods like Read<T> which seems to be what I want, except that I manually have to keep track of where in the file I want to read. 它提供了类似Read<T> ,这似乎是我想要的,除了我手动必须跟踪我想要读取的文件中的位置。 Is there a better way? 有没有更好的办法?

public static class StreamExtensions
{
    public static T ReadStruct<T>(this Stream stream) where T : struct
    {
        var sz = Marshal.SizeOf(typeof(T));
        var buffer = new byte[sz];
        stream.Read(buffer, 0, sz);
        var pinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        var structure = (T) Marshal.PtrToStructure(
            pinnedBuffer.AddrOfPinnedObject(), typeof(T));
        pinnedBuffer.Free();
        return structure;
    }
}

You need to ensure your struct is declared with [StructLayout] and possibly [FieldOffset] annotations to match the binary layout in the file 您需要确保使用[StructLayout]和可能的[FieldOffset]注释声明结构以匹配文件中的二进制布局

EDIT: 编辑:

Usage: 用法:

SomeStruct s = stream.ReadStruct<SomeStruct>();

Here is a slightly modified version of Jesper's code: 这是Jesper代码的略微修改版本:

public static T? ReadStructure<T>(this Stream stream) where T : struct
{
    if (stream == null)
        return null;

    int size = Marshal.SizeOf(typeof(T));
    byte[] bytes = new byte[size];
    if (stream.Read(bytes, 0, size) != size) // can't build this structure!
        return null;

    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try
    {
        return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    }
    finally
    {
        handle.Free();
    }
}

It handles EOF cases successfully as it returns a nullable type. 它成功处理EOF案例,因为它返回一个可空类型。

It's possible to do something similar in C#, but then you would have to apply a lot of attributes to a structure so that you control exactly how it's laid out in memory. 可以在C#中执行类似的操作,但是您必须将大量属性应用于结构,以便您可以精确控制它在内存中的布局方式。 By default the JIT compiler controls how structure members are laid out in memory, which usually means that they are rearranged and padded for the most efficient layout considering speed and memory usage. 默认情况下,JIT编译器控制结构成员在内存中的布局方式,这通常意味着考虑到速度和内存使用情况,它们会重新排列并填充以实现最高效的布局。

The simplest way is usually to use the BinaryReader to read the separate members of the structure in the file, and put the values in properties in a class, ie manually deserialise the data into a class instance. 最简单的方法通常是使用BinaryReader读取文件中结构的单独成员,并将值放在类的属性中,即手动将数据反序列化为类实例。

Normally it's reading the file that is the bottle neck in this operation, so the small overhead of reading the separate members doesn't affect the performance noticeably. 通常它正在读取此操作中的瓶颈文件,因此读取单独成员的小开销不会显着影响性能。

There is no similar way in C#. C#中没有类似的方法。 Moreover, this is deprecated way of serializing due to its non-portability. 此外,由于其不可移植性,这是不推荐的序列化方式。 Use http://www.codeproject.com/KB/cs/objserial.aspx instead. 请改用http://www.codeproject.com/KB/cs/objserial.aspx

Just to elaborate on Guffa's and jesperll's answer, here a sample on reading in the file header for a ASF (WMV/WMA) file using basically the same ReadStruct method (just not as extension method) 只是详细说明Guffa和jesperll的答案,这里是一个使用基本相同的ReadStruct方法(仅作为扩展方法)读取ASF(WMV / WMA)文件的文件头中的示例

MemoryStream ms = new MemoryStream(headerData);
AsfFileHeader asfFileHeader = ReadStruct<AsfFileHeader>(ms);


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
internal struct AsfFileHeader
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    public byte[] object_id;
    public UInt64 object_size;
    public UInt32 header_object_count;
    public byte r1;
    public byte r2;
}

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

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