 |
|
|
 |
|
 |
I believe this should be the fastest way to get a byte[] from a string, in case you need to convert a lot of substrings from the original string.
I had this problem with parsing different parts of a hex string to a byte[], so I noticed the String.SubString method is creating a bunch of new objects, slowing things down. Since there was lots of processing (~500k of characters with ~50k of small substrings) I implemented it this way.
Note that the inner loop only has few compare and add operations, and a single multiplication, to make it as fast as I could (feel free to suggest additional improvements - but without unsafe code please):
public static class Conversion { static readonly byte offset_0 = (byte)'0'; static readonly byte offset_A = (byte)'A'; static readonly byte offset_A16 = (byte)(offset_A - 10); static readonly byte offset_a = (byte)'a'; static readonly byte offset_a16 = (byte)(offset_a - 10);
public static byte[] StringToByteArray(string hex, int start, int length) { Debug.Assert(length % 2 == 0);
byte[] bytes = new byte[length / 2];
int idx = 0; int end = start + length;
for (int i = start; i < end; i += 2) { byte highNibble = (byte)hex[i]; if (highNibble >= offset_a) highNibble -= offset_a16; else if (highNibble >= offset_A) highNibble -= offset_A16; else highNibble -= offset_0;
byte lowNibble = (byte)hex[i + 1]; if (lowNibble >= offset_a) lowNibble -= offset_a16; else if (lowNibble >= offset_A) lowNibble -= offset_A16; else lowNibble -= offset_0;
bytes[idx++] = (byte)(16 * highNibble + lowNibble); } return bytes; } }
It hurts my eye to see this type of coding also! 
But: by passing the start character + length to the method, you can avoid creating a new substring, because you simply peek at individual characters. I haven't done a real benchmark, but CLRProfiler would actually hang while counting all string allocations in the previous version! :D
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Processing a large file went from more than 8 minutes to less than a second when I modified GetBytes() as shown below. A profiler showed that
System.String.Concat(Object, Object) was using most of the CPU time. Rather than concatenate or StringBuild a temporary string of valid hex digits, I just process them as they occur in the input hexString.
So far all tests have passed...
(I had no need for out int discarded and removed it.)
public static byte[] GetBytes(string hexString) {
if (null == hexString) return new byte[0]; if (hexString.Length < 2) return new byte[0];
List<byte> byteList = new List(hexString.Length/2); char c1 = 'x'; bool have1 = false;
for (int i = 0; i < hexString.Length; i++) { char c = hexString[i]; if (Uri.IsHexDigit(c)) if (have1) { byteList.Add(HexToByte(new string(new char[] {c1, c}))); have1 = false; } else { have1 = true; c1 = c; } } return byteList.ToArray(); }
modified on Thursday, January 22, 2009 5:42 PM
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
 |
I got a error from your code. (VS2008)
Fix:
Find:
List<byte> byteList = new List(hexString.Length/2); Replace:
List<byte> byteList = new List<byte>(hexString.Length / 2);
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
What about the speed and simplicity of my function :
private Byte[] hexStringToByteArray(string hexinput) { if (hexinput == String.Empty) return null; if (hexinput.Length % 2 == 1) hexinput = "0" + hexinput; int arr_size = hexinput.Length / 2; Byte[] myBytes = new Byte[arr_size]; for (int i = 0; i < arr_size; i++) myBytes[i] = Convert.ToByte(hexinput.Substring(i * 2, 2), 16); return myBytes; }
private void test() { string hex = "15900fF654654651516ABCDEFFF"; byte[] res = this.hexStringToByteArray(hex); string disp = String.Empty; foreach (byte b in res) disp += b.ToString("X2") + " - " + b.ToString() + Environment.NewLine; MessageBox.Show(disp); }
"Nothing happens unless first a dream...", Carl Sandburg
-- modified at 7:14 Monday 12th November, 2007
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
your source code was inspirational in my project.. i solved my problem, about from stringHex to byte array.. later that a great many fight.. and i find what is problem.. when i was encrypt my data :
public string WriteHex(byte[] array) { string from_array=null;
for (int i = 0; i < array.Length; i++) from_array+=array[i].ToString("X"); /* there is single X, its wrong! that's right from_array+=array[i].ToString("X2"); .... */ return from_array; }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
May be BitConverter do most of this, from and to string.
regards Michail
http://www.mommosoft.com
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
 |
Exactly. Here is an example of a function that does return a byte[] using this method.
private static byte[] HexToData(string hexString) { if (hexString == null) return null;
if (hexString.Length % 2 == 1) hexString = '0' + hexString; byte[] data = new byte[hexString.Length / 2];
for (int i = 0; i < data.Length; i++) data[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
return data; }
It is better to use this than the code from the article.
Edit: Changed byte.Parse(string, System.Globalization.NumberStyles.HexNumber) to Convert.ToByte(string, 16). This gives about a 60% to 65% performance increase to the entire method.
modified on Wednesday, April 16, 2008 11:18 AM
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|
 |
What about the code:
System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider(); byte[] key = new byte[1024]; rng.GetNonZeroBytes(key);
string ba_as_string = BitConverter.ToString(key); string[] hexaInfo = ba_as_string.Split('-'); System.Collections.ArrayList ba1 = new System.Collections.ArrayList(); foreach (string hexa in hexaInfo) ba1.Add(Convert.ToByte(hexa, 16)); byte[] ba2 = (byte[])ba1.ToArray(typeof(byte));
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
 |
This does not do what it says on the tin, i.e. convert a string into a byte[]. This generates a sequence of bytes, converts them to a string, splits them into a string[] and then individually converts them. This would be useful if and only if you are passing in a string of the format FF-FF-...-FF (imagine that ba_as_string is an argument rather than generated inside the method and ba2 is returned from the method). The vast majority of cases will use the format FFFF...FF or 0xFFFF...FF.
However, after some testing I have found that Convert.ToByte is significantly faster than byte.Parse so I have modified my previous post to use this method. This allows my method to accept FFFF...FF format and, of course, if it is 0xFFFF...FF format, you can just cut off the 0x as you pass the hex string into the method. This cut execution time on 1 million iterations of a 116 character string from an average of 8.237 seconds to an average of 4.961 seconds on my machine, which is approximately 65% faster.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi,
I don't know if I totally agree with you on the format argument... probably it would be more frequent to see stuff like 0xFF-0xFF... and so forth...
No matter, we are discussing small potatoes here, the point was that this is not really a *big* problem and there are several ways to, so to say, "kill the rabbit"... 
For example, the following reduces the "for" cycle by half:
string ba_as_string_canonical = ba_as_string.Replace("-", string.Empty);
byte[] ba3 = new byte[ba_as_string_canonical.Length / 2]; for (int i = 0; i < ba_as_string_canonical.Length; i+=2 ) ba3[i/2] = Convert.ToByte(ba_as_string_canonical.Substring(i, 2), 16);
Thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I have never seen it stored in the format FF-FF or 0xFF-0xFF as this is just a waste of space. For example most databases will represent their blobs as 0xFFFF when human readability is desired, text (hex, rather than base64 obviously) representation of things like hashes is always in the format 0xFFFF or just FFFF, etc. An example of this is the format of an MD5sum file such as this one.
It is standard for the number of characters to be twice the number of bytes but my snippet also pads the first or last byte with a 0 if this is not the case, for example "fff" can be padded to "0fff" or "ff0f" and then treated normally. (The endianness of the data specifies whether "fff" should be treated as 15,255 or 255,15 but you cannot tell this just from the string)
My snippet also already uses the same number of iterations in the for loop as the snippet you have just posted. It just creates a byte array half the length of the string and loops for each of those bytes incrementing by 1, multiplying by 2 to get the string offset rather than dividing by 2 to get the index offset and incrementing by 2. Essentially I am doing "for each byte in the destination array" and you are doing "for each pair of characters in the source string" . In days of old, this would have been a better way of doing it (* rather than /, ++ rather than += 2 etc) but I suspect that modern compilers and modern machines mean that the difference in performance is negligible, particularly on a managed environment. Regardless, I think that it is slightly more readable and any performance benefit that doesn't reduce readability is always a bonus.
As you have shown, you can pass a string in the format FF-FF or even 0xFF-0xFF into my method anyway simply by replacing the - or "0x" with String.Empty. The only problem with this is that F-FF should clearly be treated as 0FFF while FF-F should clearly be treated as FF0F, so any implied endianness is lost when the -s are removed. Obviously not a problem if it is FF-0F in the first place. Ideally, if you know in advance that the string is in the format FF-FF, your code that splits on '-' is better. In all other cases, it is not usable.
The point really is that there are many ways of doing this that are better than the code in the article.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
The argument range is limited by Int32.MaxValue and Int32.MinValue. "fae0b7abcd" will throw an OverflowException.
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|
 |
I needed this so that I could easily convert Hex into a Byte Array. Once converted to a byte array I sent the byte packet out of a serial port to control my Pan Tilt Zoom camera pod. This class made that conversion very very simple to do.
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
 |
using System; using System.Collections.Generic; using System.Text;
namespace Utilities { public class MyHexConverter { /// <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" }; static byte[] HSTB = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 }; /// <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> public static string ByteArrayToHexString(byte[] ArrayToConvert, string Delimiter) { int LengthRequired = ArrayToConvert.Length << 1 + Delimiter.Length * ArrayToConvert.Length + 1; StringBuilder tempstr = new StringBuilder(LengthRequired, LengthRequired); foreach (byte CurrentElem in ArrayToConvert) { tempstr.Append(BATHS[CurrentElem]); tempstr.Append(Delimiter); } tempstr.Remove(tempstr.Length - 1, 1); return tempstr.ToString(); }
/// <summary> /// Function converts given hexadecimal string to it's binary representation /// </summary> /// <param name="StringToConvert">String to convert to byte array</param> /// <returns>Byte array representing given string</returns> public static byte[] PureHexStringToByteArray(string StringToConvert) { byte[] temparr = new byte[StringToConvert.Length / 2]; byte Char1, Char2; for (int i = 0; i < StringToConvert.Length; i = i + 2) { Char1 = (Byte)StringToConvert[i]; Char2 = (Byte)StringToConvert[i + 1]; temparr[i / 2] = (Byte)((HSTB[(Char1 - 48)] << 4) + HSTB[(Char2 - 48)]); } return temparr; } } }
|
| Sign In·View Thread·PermaLink | 2.67/5 (3 votes) |
|
|
|
 |
|
 |
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" };
public static string ByteArrayToHexString(byte[] ArrayToConvert, char Delimiter) { char[] list = new char[ArrayToConvert.Length * 3];
for (int k = 0; k < ArrayToConvert.Length; ++k) { list[k * 3 + 0] = BATHS[ArrayToConvert[k]][0]; list[k * 3 + 1] = BATHS[ArrayToConvert[k]][1]; list[k * 3 + 2] = Delimiter; }
return new string(list); }
|
| Sign In·View Thread·PermaLink | 2.00/5 (2 votes) |
|
|
|
 |
|
|
 |
|
 |
is that your HexEncoding will support big endian hex numbers? for example, the header signature of JPG file is 0x04034b50 and HexEncoding will convert this as { 4,3,75,80 } - which is correct. But, any way to provide a functionality to convert bigendian hex. It would be great thing to have in there.
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|