C # reading structures from a binary file

I want to read structures from binary files. In C ++, I would do it like this:

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

Is there a similar way in C #? BinaryReader works only for built-in types. .NET 4 has a MemoryMappedViewAccessor. It provides methods like Read<T> , which seems to be what I want, except that I have to manually track where in the file I want to read. Is there a better way?

+6
c # file binary structure
source share
5 answers

In C #, you can do something similar, but then you will need to apply a lot of attributes to the structure so that you accurately determine how it stacks in memory. By default, the JIT compiler controls how structure elements are placed in memory, which usually means that they are rearranged and supplemented for the most efficient layout, given the speed and memory usage.

The easiest way is to use BinaryReader to read the individual elements of the structure in the file and put the values ​​in the properties of the class, i.e. manually deserialize the data into an instance of the class.

Usually he reads a file that is the neck of the bottle in this operation, so the small overhead of reading individual items does not affect performance noticeably.

+2
source share
 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 make sure your structure is declared using the [StructLayout] and possibly [FieldOffset] annotations to match the binary layout in the file

EDIT:

Using:

 SomeStruct s = stream.ReadStruct<SomeStruct>(); 
+13
source share

There is no similar method in C #. Moreover, this is an obsolete serialization method due to its intolerance. Use http://www.codeproject.com/KB/cs/objserial.aspx instead.

+1
source share

To talk about Guffa and jesperll in detail, here is an example of reading in the file header for the ASF file (WMV / WMA), using basically the same ReadStruct method (and not as an extension method)

 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; } 
+1
source share

Here is a slightly modified version of Jesper code:

 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 successfully handles EOF cases when it returns a type with a null value.

+1
source share

All Articles