Click here to Skip to main content
15,884,388 members
Articles / Programming Languages / C#

Quick and Dirty HexDump of a Byte Array

Rate me:
Please Sign up or sign in to vote.
4.14/5 (14 votes)
25 Jan 2012CPOL2 min read 96.1K   33   30
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:

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

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

C#
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

C#
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 ? '·' : (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.

 

C#
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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
France France
I am a French programmer.
These days I spend most of my time with the .NET framework, JavaScript and html.

Comments and Discussions

 
QuestionCan you help to connect it with serial-port? Pin
JeezyWonder8-Feb-17 20:09
JeezyWonder8-Feb-17 20:09 
QuestionGreat work Pin
jcxtsoftware8-Mar-16 4:20
jcxtsoftware8-Mar-16 4:20 
AnswerRe: Great work Pin
Pascal Ganaye17-Mar-16 23:36
Pascal Ganaye17-Mar-16 23:36 
The Linq" version is not my favourite. I find it harder to read.
Here is a single line version:
hexDump = (Func<byte[], string>)(bytes => String.Join(Environment.NewLine, bytes.Select((b, i) => new { b, i })
    .GroupBy(p => p.i / 16).Select(l =>
    string.Format("{0:x8} {1,-50} {2,-16}",
        l.Key,
        String.Concat(l.Select(p => ((p.i & 7) == 0 ? "  " : " ") + p.b.ToString("x2")).ToArray()),
        new String(l.Select(p => p.b < 32 ? '.' : (char)p.b).ToArray()))).ToArray()));

QuestionA bug Pin
Constantine Kharlamov10-Aug-15 23:31
Constantine Kharlamov10-Aug-15 23:31 
AnswerRe: A bug Pin
Pascal Ganaye19-Aug-15 9:35
Pascal Ganaye19-Aug-15 9:35 
GeneralRe: A bug Pin
Constantine Kharlamov22-Aug-15 21:31
Constantine Kharlamov22-Aug-15 21:31 
GeneralRe: A bug Pin
Pascal Ganaye23-Aug-15 20:51
Pascal Ganaye23-Aug-15 20:51 
GeneralRe: A bug Pin
Constantine Kharlamov23-Aug-15 21:12
Constantine Kharlamov23-Aug-15 21:12 
GeneralRe: A bug Pin
Pascal Ganaye31-Aug-15 3:53
Pascal Ganaye31-Aug-15 3:53 
GeneralRe: A bug Pin
Constantine Kharlamov31-Aug-15 4:08
Constantine Kharlamov31-Aug-15 4:08 
QuestionPrinting of byte value 7F Pin
Craig McQueen17-Mar-15 16:44
Craig McQueen17-Mar-15 16:44 
General5 - Very Useful!! Pin
jedidja10-Aug-14 2:59
jedidja10-Aug-14 2:59 
General5 Pin
acryll17-Oct-13 23:50
acryll17-Oct-13 23:50 
GeneralMy vote of 5 Pin
sooqua7511-May-13 5:01
sooqua7511-May-13 5:01 
Suggestion[My vote of 2] Why not just use the builtin version in the framework ? Pin
Paw Jershauge27-Jan-12 1:14
Paw Jershauge27-Jan-12 1:14 
GeneralRe: [My vote of 2] Why not just use the builtin version in the framework ? Pin
Pascal Ganaye27-Jan-12 3:48
Pascal Ganaye27-Jan-12 3:48 
GeneralMy vote of 1 Pin
frankazoid22-Nov-11 9:35
frankazoid22-Nov-11 9:35 
GeneralFixed Pin
Pascal Ganaye25-Jan-12 12:18
Pascal Ganaye25-Jan-12 12:18 
QuestionIs it a typing error? Pin
Anjum Latif12-Jul-10 3:38
Anjum Latif12-Jul-10 3:38 
GeneralMy vote of 4 Pin
xExTxCx2-Jul-10 13:50
xExTxCx2-Jul-10 13:50 
GeneralI like it. Pin
Alastair Taylor17-Jun-10 0:58
Alastair Taylor17-Jun-10 0:58 
Generalshift too much? [modified] Pin
lobmayer6-Nov-09 4:30
lobmayer6-Nov-09 4:30 
GeneralToo quick too dirty Pin
Pascal Ganaye6-Nov-09 22:25
Pascal Ganaye6-Nov-09 22:25 
GeneralI like it! Pin
Sjackson20822-Jun-09 4:24
Sjackson20822-Jun-09 4:24 
GeneralRe: I like it! Pin
Sjackson20822-Jun-09 6:39
Sjackson20822-Jun-09 6:39 

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.