繁体   English   中英

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

[英]C#, read structures from binary file

我想从二进制文件中读取结构。 在C ++中,我会这样做:

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

在C#中是否有类似的方式? BinaryReader仅适用于内置类型。 在.NET 4中有一个MemoryMappedViewAccessor。 它提供了类似Read<T> ,这似乎是我想要的,除了我手动必须跟踪我想要读取的文件中的位置。 有没有更好的办法?

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;
    }
}

您需要确保使用[StructLayout]和可能的[FieldOffset]注释声明结构以匹配文件中的二进制布局

编辑:

用法:

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

这是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();
    }
}

它成功处理EOF案例,因为它返回一个可空类型。

可以在C#中执行类似的操作,但是您必须将大量属性应用于结构,以便您可以精确控制它在内存中的布局方式。 默认情况下,JIT编译器控制结构成员在内存中的布局方式,这通常意味着考虑到速度和内存使用情况,它们会重新排列并填充以实现最高效的布局。

最简单的方法通常是使用BinaryReader读取文件中结构的单独成员,并将值放在类的属性中,即手动将数据反序列化为类实例。

通常它正在读取此操作中的瓶颈文件,因此读取单独成员的小开销不会显着影响性能。

C#中没有类似的方法。 此外,由于其不可移植性,这是不推荐的序列化方式。 请改用http://www.codeproject.com/KB/cs/objserial.aspx

只是详细说明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