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

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

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

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

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

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

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

 public static class StreamExtensions { public static T ReadStruct(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(); 

这是Jesper代码的略微修改版本:

 public static T? ReadStructure(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#中没有类似的方法。 此外,由于其不可移植性,这是不推荐的序列化方式。 请改用http://www.codeproject.com/KB/cs/objserial.aspx 。

只是详细说明Guffa和jesperll的答案,这里是一个使用基本相同的ReadStruct方法(仅作为扩展方法)读取ASF(WMV / WMA)文件的文件头的示例

 MemoryStream ms = new MemoryStream(headerData); AsfFileHeader asfFileHeader = ReadStruct(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; }