Answered by:
byte[] Array to Hex String

Question
-
Answers
All replies
-
-
-
-
Faster variant:
public class JSMHexConverter
{
/// <summary>
/// Helper array to speedup conversion
/// </summary>
static string[] BATHS = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };
/// <summary>
/// Function converts byte array to it's hexadecimal implementation
/// </summary>
/// <param name="ArrayToConvert">Array to be converted</param>
/// <param name="Delimiter">Delimiter to be inserted between bytes</param>
/// <returns>String to represent given array</returns>
static string ByteArrayToHexString(byte[] ArrayToConvert, string Delimiter)
{
int LengthRequired = (ArrayToConvert.Length + Delimiter.Length) * 2;
StringBuilder tempstr = new StringBuilder(LengthRequired, LengthRequired);
foreach(byte CurrentElem in ArrayToConvert)
{
tempstr.Append(BATHS[CurrentElem]);
tempstr.Append(Delimiter);
}
return tempstr.ToString();
}
} -
Here's my function:
public static string HexStr(byte[] p) {
char[] c=new char[p.Length*2 + 2];
byte b;
c[0]='0'; c[1]='x';
for(int y=0, x=2; y<p.Length; ++y, ++x) {
b=((byte)(p[y ]>>4));
c[x]=(char)(b>9 ? b+0x37 : b+0x30);
b=((byte)(p[y ]&0xF));
c[++x]=(char)(b>9 ? b+0x37 : b+0x30);
}
return new string(c);
}
it puts "0x" at the beginning of the string, but that's a simple matter to change.HexStr(new byte[]{0x00,0xDE,0xAD,0xBE,0xEF,0x99}) ==> "0x00DEADBEEF99"
Sorry to cut you off up there, but when dealing with big arrays, every character - every processor cycle - counts.- Proposed as answer by R Shillington Saturday, May 31, 2008 11:13 AM
-
-
If I caught anyone using anything but BitConverter.ToString and trying to roll their own solution, I would fire them on the spot.
If I caught anyone necroing 18-month old threads to make macho threats, I'd fire them on the spot.
Especially if the answer they gave was already posted in that thread almost three years before...
:)
-
-
If I would order an application with you, and the preocess takes 40 time longer, because your team has to use BitConverter instead of any other clean approach, I would never give you a job again.
In my case we convert thousands of times a few thousand bytes, all that while the user is operating the PC. I made some time measurements:
BitConverter + String.Replace("-", ""): 203407
Fractals mapping approach: 6609
PZahras approach: 4903
I can not understand how you justify, to fire a good developer and deliver a solution which takes 40 times as long.
In my opinion all 3 approaches are good, depending on your problem, the solution may totally differ. None of the solutions uses unsafe code, so I can not see how it would interfere with any clean code policies.
Thank you all for your great solutions :-) -
-
hi use thisstring hexString = string.Empty;for (int i=0; i<bytes.Length; i++){hexString += bytes[i].ToString("X2");}return hexString;
Well done sandeeprwt - I have used this in my code and it works brilliantly. Simple, elegant and efficient - what is it that makes developers go for the most complex solutions when you can do something like this. If you used the stringbuilder though that would be even better because the += has to create a new string each time.
StringBuilder sb = new StringBuilder();for (int i = 0; i < _data.Length; i++)
{
sb.Append(bites[i].ToString("X2"));
}return sb.ToString();
As for gurhalls comments - I'd fire him on the spot for NOT thinking up a solution like this because it proves he hasnt got the necessary skills to be a decent developer. I am assuming he is some form of a manager - speaks volumes doesn't it! -
Is there an equally simple solution to go from Hexstring to Byte[] or even to int?
By the way, I had a manager like the above mentioned. He went through several "unqualified" engineers and myself before he "left" the company because he could not handle the stress (was driven out). -
There's an easy one to go from a hex string to an int, but not from hex string to array of bytes:
using System; using System.Diagnostics; using System.Globalization; namespace ConsoleApplication1 { static class Program { static void Main() { // Convert from hex string to int using int.Parse(): string hexInt = "ABCD1234"; int number = int.Parse(hexInt, NumberStyles.HexNumber); Console.WriteLine(number.ToString("X")); // Convert from hex string to byte array using a custom method: string hexString = "0102030405060708090a0b0c0d0e0fAAABACADAEAF"; byte[] bytes = HexStringToBytes(hexString); string converted = BitConverter.ToString(bytes).Replace("-", null); Console.WriteLine(converted); Debug.Assert(string.Compare(converted, hexString, true) == 0); } static byte[] HexStringToBytes(string hexString) { if (hexString == null) { throw new ArgumentNullException("hexString"); } if ((hexString.Length & 1) != 0) { throw new ArgumentOutOfRangeException("hexString", hexString, "hexString must contain an even number of characters."); } byte[] result = new byte[hexString.Length/2]; for (int i = 0; i < hexString.Length; i += 2) { result[i/2] = byte.Parse(hexString.Substring(i, 2), NumberStyles.HexNumber); } return result; } } }
-
-
Actually; the real problem is MS should be providing a proper .net component to handle low level byte mapping. I know they want us "amateurs" to use more abstract components (eg Encoder, StreamWriter, etc), but sometimes all I want to do is a "hello world" app without needing to write a gigantic library to do something as basic as converting byte arrays.
-
-
-
-
If you're looking for pure speed try:public static string HexStr(byte[] data){char[] lookup = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };int i = 0, p = 2, l = data.Length;char[] c = new char[l * 2 + 2];byte d; c[0] = '0'; c[1] = 'x';while (i < l){d = data[i++];c[p++] = lookup[d / 0x10];c[p++] = lookup[d % 0x10];}return new string(c, 0, c.Length);}Which works out about 30% faster than PZahras (not that you'd notice with small amounts of data).The BitConverter method itself is pretty quick, it's just having to do the replace which slows it down, so if you can live with the dashes then it's perfectly good.
- Proposed as answer by PZahra Monday, April 19, 2010 5:26 PM
-
Oh, well done, Fraser. Fast is good. Of course, reading from text is always going to be slower...
public static byte[] HexByte(string str, int offset, int step, int tail) { byte[] b = new byte[(str.Length - offset - tail + step) / (2 + step)]; byte c1, c2; int l = str.Length - tail; int s = step + 1; for(int y = 0, x = offset; x < l; ++y, x += s) { c1 = (byte)str[x]; if(c1 > 0x60) c1 -= 0x57; else if(c1 > 0x40) c1 -= 0x37; else c1 -= 0x30; c2 = (byte)str[++x]; if(c2 > 0x60) c2 -= 0x57; else if(c2 > 0x40) c2 -= 0x37; else c2 -= 0x30; b[y] = (byte)((c1 << 4) + c2); } return b; }
... Especially if you're going to make it case insensitive. I added the offset so as to not waste time with substring when you want to ignore the 0x, &H, $, #, Hex(...) or whatever other symbol is used. Also, step to ignore spacing and tail to cut off quotes and stuff at the end. I didn't fully test this, so enjoy. -
actually it has a little error.
if you have a string like this: "12 34 56 78" your "step" will be one.
but when you calculate the byte array size you don't take this into account. So, you will have a 11/2 = 5 size array.
so, we need to put like this:
byte[] b = new byte[(str.Length - offset - tail) / (2 + step)];
but, it is not enough. If the string is exactly like i said before the result will be 3 because using the "+ step" take into account a space in the end of the last element (string). So the solution for this can take several verifications and can be done in several ways. Maybe the easy way is to make mandatory an odd string, or add a space at the end (maybe showing a Alert Box to the user asking if it is the right thing to do)
any doubts, just ask.
sorry for some English errors, not my natural language.
-
-
Hey guys, here is another variant using bitwise operations (i love them :D) it's based on matthews code.
public static string HexStr(byte[] data)
{
char[] lookup = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
StringBuilder sb = new StringBuilder(data.Length * 2);
for(int buc = 0; buc < data.Length; buc++){
sb.Append(lookup[(data[buc] >> 4) & 0x0F]);
sb.Append(lookup[data[buc] & 0x0F]);
}
return sb.ToString();
} -
1. Lookup tables should always be static. When you declare them inside a method, they get allocated on the heap every time the method is called.
2. Temporary arrays should be allocated on the stack for the same reason. Just be careful of the 1MB stack limit. That's why this example uses sbyte instead of char.
You may not see a significant speed increase, but the only object that get allocated by the runtime is the string itself.
private static readonly sbyte[] _lookup = new sbyte[] { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; public static unsafe string ToHex(this byte[] arr) { int len = arr.Length; int i = 0; sbyte* chars = stackalloc sbyte[len * 2]; fixed (byte* pSrc = arr) { byte* pIn = pSrc; sbyte* pOut = chars; while (i++ < len) { *pOut++ = _lookup[*pIn >> 4]; *pOut++ = _lookup[*pIn++ & 0xF]; } } return new String(chars, 0, len * 2); }
-
If I caught anyone using anything but BitConverter.ToString and trying to roll their own solution, I would fire them on the spot.
If I caught anyone necroing 18-month old threads to make macho threats, I'd fire them on the spot.
Especially if the answer they gave was already posted in that thread almost three years before...
:)
LOL, then just fire me Mr. Donald Trump wanna be:here is a Linq solution, probably more elegant than the BitConverter:
public static class HelperTools { public static string ToHexString(this IEnumerable<byte> bytes) { return new string(bytes.SelectMany(x => x.ToString("X2").ToCharArray()).ToArray()); } } //and you use it like this: Byte[] Bytes = {0xFF, 0xD0, 0xFF, 0xD1} ; string hexstr = Bytes.ToHexString();
Now Mr. trump is waiting in the board room! Who's gonna get fired?
- Edited by dmihailescu Friday, February 4, 2011 4:38 PM code block
-
-
Hello all,
Sorry for refreshing a thread that is so old but I basically want to do similar thing that has been asked here only I want the byte[] array to be parsed as a .reg file. Moreover I want to do it in NETCF on PocketPC.
What I do is to take a value from registry:RegistryKey RgKey = Registry.LocalMachine.OpenSubKey("\Time") string RgName = "TimeZoneInformation" string ValueType = Convert.ToString(RgKey.GetValueKind(RgName)); obj Value = RgKey.GetValue(RgName);
(I know the ValueType and Value variables don't make any sense assigned this way, but what I need to get is a unicode text file (a .reg file) with something like this:
[HKEY_LOCAL_MACHINE\Time] "TimeZoneInformation"=hex:c4,ff,ff,ff,45,00,75,00,72,00,6f,00,70,00,61,00,20,\ 00,5a,01,72,00,6f,00,64,00,6b,00,6f,00,77,00,61,00,20,00,28,00,63,00,7a,00,61,\ 00,73,00,20,00,73,00,74,00,61,00,6e,00,64,00,2e,00,29,00,00,00,00,00,00,00,00,\ 00,0a,00,00,00,05,00,03,00,00,00,00,00,00,00,00,00,00,00,45,00,75,00,72,00,6f,\ 00,70,00,61,00,20,00,5a,01,72,00,6f,00,64,00,6b,00,6f,00,77,00,61,00,20,00,28,\ 00,63,00,7a,00,61,00,73,00,20,00,6c,00,65,00,74,00,6e,00,69,00,29,00,00,00,00,\ 00,00,00,00,00,00,00,03,00,00,00,05,00,02,00,00,00,00,00,00,00,c4,ff,ff,ff
I know how to parse the key name (it's the easiest task), and I even have the idea to make a condition for showing the type of the data properly. But I have no idea how to parse the "Value" to have the notation like in the above example...
Do you think you can help me? -
-
Honestly I parsed the line breaks with a bit "manual" method. After a few nights of thinking (perhaps I'm just not smart enough to do it sooner) I realized that it's a matter of formatting string and not of converting it. And here's what I did:
RegistryKey RgKey = Registry.LocalMachine.OpenSubKey("\\Time"); string RgName = "Time"; string Txt = null; string Tmp = null; byte[] data = (byte[])RgKey.GetValue(RgName); for (int i = 0; i < data.Length; i++) { if (i % 24 == 0) Tmp = Tmp + "\\\n"; Tmp = Tmp + String.Format("{0:X2}", data[i]); if (i < data.Length - 1) Tmp = Tmp + ","; } Txt = RgName + "=hex:" + Tmp; break;
It was easier than I thought. I hope this will come in handy to someone else.
-
-
-
If there is no need to give an answer, then why not just remove the thread. This is the thinking that results in hours of wasted time reading threads that have no answers. I am reading this thread 7 years later, and I greatly appreciate all the solutions given. Threads like this are meant to be read by the general public years after the initial discussion. Otherwise we will just keep asking the same question over and over.
-
Thanks to timster at home. I decided to use his solution (using StringBuilder) in my project. To all those reading this thread (years later), the information given is still relevant and useful. Remember, however, that the .net language is still evolving so you may want to check more recent solutions. BTW I prefer StringBuilder because I am developing a serial port program and I don't want to keep creating new strings every time new data comes in. If you don't understand this, check into the idea of C++ strings being immutable.
-
-
I concur on the timing (sort of).
Timed it on .NET 4.5
What I was after is the fastest solution for converting byte[] into a hex string with no delimiters
Of the solutions posted so far, the two competing for the first place are Fractal's and Frasier's improvement on PZahras
Both are about 3 times faster than BitConverter.ToString(...).Replace("-", "")
For interested parties here is the code I was timing. It converts a stream (from say an image file) into a string of hex with line breaks every 256 bytes.
StreamToHex2 and StreamToHex3 are both faster than StreamToHex
public static string StreamToHex(Stream stream)
{
stream.Seek(0, 0);
BinaryReader reader = new BinaryReader(stream);
StringBuilder imageInHex = new StringBuilder();
byte[] buffer = new byte[256];
int bytesread = reader.Read(buffer, 0, buffer.Length);
while (bytesread != 0)
{
imageInHex.AppendLine(BitConverter.ToString(buffer, 0, bytesread).Replace("-", ""));
bytesread = reader.Read(buffer, 0, buffer.Length);
}
return imageInHex.ToString();
}
public static string StreamToHex2(Stream stream)
{
stream.Seek(0, 0);
BinaryReader reader = new BinaryReader(stream);
StringBuilder imageInHex = new StringBuilder();
byte[] buffer = new byte[256];
int bytesread = reader.Read(buffer, 0, buffer.Length);
while (bytesread != 0)
{
for (int i = 0; i < bytesread; i++)
imageInHex.Append(BATHS[buffer[i]]);
imageInHex.AppendLine();
bytesread = reader.Read(buffer, 0, buffer.Length);
}
return imageInHex.ToString();
}
public static string StreamToHex3(Stream stream)
{
stream.Seek(0, 0);
BinaryReader reader = new BinaryReader(stream);
StringBuilder imageInHex = new StringBuilder();
byte[] buffer = new byte[256];
int bytesread = reader.Read(buffer, 0, buffer.Length);
while (bytesread != 0)
{
imageInHex.AppendLine(HexStr2(buffer, bytesread));
bytesread = reader.Read(buffer, 0, buffer.Length);
}
return imageInHex.ToString();
}
public static string HexStr(byte[] p, int length)
{
char[] c = new char[length * 2];
byte b;
for (int y = 0, x = 0; y < length; ++y, ++x)
{
b = ((byte)(p[y] >> 4));
c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(p[y] & 0xF));
c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
public static string HexStr2(byte[] data, int length)
{
char[] lookup = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
int i = 0, p = 0;
char[] c = new char[length * 2];
byte d;
while (i < length)
{
d = data[i++];
c[p++] = lookup[d / 0x10];
c[p++] = lookup[d % 0x10];
}
return new string(c, 0, c.Length);
}
static string[] BATHS = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };
P.S. I originally timed it using the Profiler with Sampling. I then tried Instrumentation and found that the version that uses BATHS array is actually shown as slower. I suspect that instrumentation overhead is the culprit here, but to stay on the safe side I opted for StreamToHex3 variant that I further improved like so:
private static string BytesToHex(byte[] bytes)
{
return Environment.NewLine + HexStr(bytes, 0, bytes.Length) + Environment.NewLine ;
}//or if you need multiline
private static string BytesToHex(byte[] bytes)
{
StringBuilder imageInHex = new StringBuilder();
int length;
int MAX_LEN = 256;
for(int i = 0; i < bytes.Length;)
{
length = Math.Min(MAX_LEN, bytes.Length - i);
imageInHex.AppendLine(HexStr(bytes, i, length));
if (length < MAX_LEN)
break;
else
i += length;
}
return imageInHex.ToString();
} public static string HexStr(byte[] data, int position, int length)
{
char[] lookup = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
int i = position, p = 0;
char[] c = new char[length * 2];
byte d;
while (i < position+length)
{
d = data[i++];
c[p++] = lookup[d / 0x10];
c[p++] = lookup[d % 0x10];
}
return new string(c, 0, c.Length);
}- Edited by ilia.broudno Thursday, December 4, 2014 7:37 PM