Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Quick and Dirty HexDump of a Byte Array

0.00/5 (No votes)
25 Jan 2012 8  
A simple function to transform a Byte[] into an Hex Dump formatted string

HexDump/hexdump.png

Introduction

This article offers a function that transforms a byte array into a hex dump format as shown below:

00000000   03 0D 05 05 0A 00 00 00 01  00 09 01 00 00 00 00 ?m······Á·I·····
00000010   00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 ················

It can be used in your code or in Visual Studio watch window.

Background

This is not rocket science. I rewrite this function every time I need it and I believe it is time to store it in a place where I can hopefully retrieve next time, that is on CodeProject.

Using the Code

For your convenience I took care of writing all the code in a single static function.

To use this code, simply copy that function in your C# solution.

Then a simple way to use the code would be:

System.Diagnostics.Debug.WriteLine(Utils.HexDump(buffer));

You can also use the function in Visual Studio Watch Window, for example:

Utils.HexDump(buffer)   

Points of Interest

There is really not much to speak about.

Each line is formatted in the same way as the Visual Studio hex dump editor.

There is a section for the Address, then the bytes in an hexadecimal format followed by the same bytes as ASCII.

//           1         2         3         4         5         6         7         8
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890
// 12345678  00 11 22 33 44 55 66 77  88 99 AA BB CC DD EE FF  0123456789ABCDEF<< 

For speed, I use my own HexChars array rather than the various built-in conversion routines.

HexChars[0] contains the character '0' up to HexChars[15] which contains the character 'F'.

You could argue that there are ways to write this in a shorter way.
Because I did not know what size of buffers you were going to use I tried to make the code as fast a possible while keeping the source readable.

Full Source

using System.Text;

namespace HexDump  
{
    class Utils
    {
        public static string HexDump(byte[] bytes, int bytesPerLine = 16)
        {
            if (bytes == null) return "<null>";
            int bytesLength = bytes.Length;

            char[] HexChars = "0123456789ABCDEF".ToCharArray();

            int firstHexColumn =
                  8                   // 8 characters for the address
                + 3;                  // 3 spaces

            int firstCharColumn = firstHexColumn
                + bytesPerLine * 3       // - 2 digit for the hexadecimal value and 1 space
                + (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th
                + 2;                  // 2 spaces 

            int lineLength = firstCharColumn
                + bytesPerLine           // - characters to show the ascii value
                + Environment.NewLine.Length; // Carriage return and line feed (should normally be 2)

            char[] line = (new String(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray();
            int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
            StringBuilder result = new StringBuilder(expectedLines * lineLength);

            for (int i = 0; i < bytesLength; i += bytesPerLine)
            {
                line[0] = HexChars[(i >> 28) & 0xF];
                line[1] = HexChars[(i >> 24) & 0xF];
                line[2] = HexChars[(i >> 20) & 0xF];
                line[3] = HexChars[(i >> 16) & 0xF];
                line[4] = HexChars[(i >> 12) & 0xF];
                line[5] = HexChars[(i >> 8) & 0xF];
                line[6] = HexChars[(i >> 4) & 0xF];
                line[7] = HexChars[(i >> 0) & 0xF];

                int hexColumn = firstHexColumn;
                int charColumn = firstCharColumn;

                for (int j = 0; j < bytesPerLine; j++)
                {
                    if (j > 0 && (j & 7) == 0) hexColumn++;
                    if (i + j >= bytesLength)
                    {
                        line[hexColumn] = ' ';
                        line[hexColumn + 1] = ' ';
                        line[charColumn] = ' ';
                    }
                    else
                    {
                        byte b = bytes[i + j];
                        line[hexColumn] = HexChars[(b >> 4) & 0xF];
                        line[hexColumn + 1] = HexChars[b & 0xF];
                        line[charColumn] = (b < 32 ? '&middot;' : (char)b);
                    }
                    hexColumn += 3;
                    charColumn++;
                }
                result.Append(line);
            }
            return result.ToString();
        }
    }
}

The case for DIY

Here is a much shorter alternative written using linq.

Viewed from the outside it seems pretty efficient as it is using a StringBuilder and native conversion and string manipulation routines.

Sadly this is 35 times slower than the first version.

I am all in favor of not reinventing the wheel and not optimizing too early or in places where it is not needed.
Please do not reinvent the wheel, use the code above, I've done it for you.

 

StringBuilder sb = new StringBuilder();
for (int line = 0; line < bytes.Length; line += bytesPerLine)
{
    byte[] lineBytes = bytes.Skip(line).Take(bytesPerLine).ToArray();
    sb.AppendFormat("{0:x8} ", line);
    sb.Append(string.Join(" ", lineBytes.Select(b => b.ToString("x2"))
           .ToArray()).PadRight(bytesPerLine * 3));
    sb.Append(" ");
    sb.Append(new string(lineBytes.Select(b => b < 32 ? '.' : (char)b)
           .ToArray()));
}
return sb.ToString();

After a few years here is some change

Due to the ubiquity of large screen nowadays, today I decided to add a new parameter int bytesPerLine = 16 to this function.

If you spend big money in a ultra wide screen you can now enjoy hexdump with as many columns a you wish. Note that the Visual Studio Immediate Window wordwraps if there are more than 245 bytes per line though.

Trace.WriteLine(HexDump(myBytes, 245));  

Apart from the large screen this feature is also convenient when you want to watch fixed width data.

History

  • 25th January 2012: Second version (changed a couple of lines) thanks to you guys. Also introduced the bytesPerLine parameter and moved it all in a single static function
  • 26th May, 2009: First version
  • 24th August 2015: Fix Environment.NewLine issue on Mono.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here