簡體   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