Click here to Skip to main content
15,505,126 members
Articles / General Programming / String
Tip/Trick
Posted 23 Apr 2021

Stats

4.6K views
9 bookmarked

A Few Missing Methods on BinaryReader

Rate me:
Please Sign up or sign in to vote.
5.00/5 (12 votes)
23 Apr 2021CPOL1 min read
BinaryReader needs a better way to read strings and types. Here's a quick and dirty fix
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.

ReadFixedString

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.

C#
using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;

/// <summary>
/// Provides some conspicuously absent string and type functionality to 
/// <seealso cref="BinaryReader"/>
/// </summary>
static class BinaryReaderExtensions
{
    /// <summary>
    /// Reads a class or a struct from the reader
    /// </summary>
    /// <typeparam name="T">The type to read</typeparam>
    /// <param name="reader">The reader</param>
    /// <returns>An instance of <typeparamref name="T"/> as read from the stream</returns>
    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;
    }
    /// <summary>
    /// Reads a C style null terminated ASCII string
    /// </summary>
    /// <param name="reader">The binary reader</param>
    /// <returns>A string as read from the stream</returns>
    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();
    }
    /// <summary>
    /// Reads a fixed size ASCII string
    /// </summary>
    /// <param name="reader">The binary reader</param>
    /// <param name="count">The number of characters</param>
    /// <returns>A string as read from the stream</returns>
    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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Just a shiny lil monster. Casts spells in C++. Mostly harmless.

Comments and Discussions

 
GeneralMy vote of 5 Pin
David A. Gray26-Apr-21 20:09
David A. Gray26-Apr-21 20:09 
I've written similar code, but hand't considered implementing a generic for objects or implementing it as an extension method, though I certainly know how to do so.
GeneralRe: My vote of 5 Pin
honey the codewitch26-Apr-21 20:42
mvahoney the codewitch26-Apr-21 20:42 
GeneralRe: My vote of 5 Pin
David A. Gray26-Apr-21 20:46
David A. Gray26-Apr-21 20:46 
SuggestionMessage Closed Pin
23-Apr-21 22:54
Member 1516779823-Apr-21 22:54 
GeneralMessage Closed Pin
23-Apr-21 22:53
Member 1516779423-Apr-21 22:53 
GeneralMy vote of 5 Pin
LightTempler23-Apr-21 21:50
LightTempler23-Apr-21 21:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.