BinaryReader often can't read strings the way they're stored in files not created with BinaryWriter, and can't easily read types an entire struct/class at a time. These quick extension methods remedy that.
Introduction
Perhaps just to prove I can trade you less than 5 minutes of your time and in return give you something useful, here you go.
BinaryReader
can't read fixed length nor ASCII null terminated strings out of streams, which is unfortunate because a whole lot of files store strings that way, for better or worse. Furthermore, there's no easy way to read data into an entire structure without reading each individual field.
I recently reimplemented this feature once again, because it seems every time I do, the code gets buried somewhere to the point where it's easier to rewrite it than to hunt it down. This tip therefore, is as much for me as it is for you, gentle reader.
Coding this Mess
This code is so short, I'm simply pasting it here for you to use.
using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
static class BinaryReaderExtensions
{
public static T ReadType<T>(this BinaryReader reader)
{
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
handle.Free();
return result;
}
public static string ReadSZString(this BinaryReader reader)
{
var result = new StringBuilder();
while (true)
{
byte b = reader.ReadByte();
if (0 == b)
break;
result.Append((char)b);
}
return result.ToString();
}
public static string ReadFixedString(this BinaryReader reader,int count)
{
return Encoding.ASCII.GetString(reader.ReadBytes(count));
}
}
Using this Mess
After pasting the above into a file in your code, simply use the BinaryReader
as you normally would, except that now you have the above methods. Keep in mind any types you want to read from a file must be able to be marshalled. This may mean actually adding marshalling attributes to your types if you want to use ReadType<>()
with them.
Reading these ASCII strings is often useful when you're dealing with older files that commonly use fixed length or null terminated ASCII to store their strings. When you encounter such a string in your stream, you can simply use the appropriate method to read it. The doc comments should make everything clear.
And that's all there is to it. Hopefully it helps you out, if not now, then somewhere down the road.
History
- 23rd April, 2021 - Initial submission