如何将hex转换为字节数组?

我复制和粘贴这个二进制数据的SQL Server,我无法在这个时候查询。

0xBAC893CAB8B7FE03C927417A2A3F6A60BD30FF35E250011CB25507EBFCD5223B 

我如何将它转换回在C#中的字节数组?

像这样的东西:

 using System; public static class Parser { static void Main() { string hex = "0xBAC893CAB8B7FE03C927417A2A3F6A6" + "0BD30FF35E250011CB25507EBFCD5223B"; byte[] parsed = ParseHex(hex); // Just for confirmation... Console.WriteLine(BitConverter.ToString(parsed)); } public static byte[] ParseHex(string hex) { int offset = hex.StartsWith("0x") ? 2 : 0; if ((hex.Length % 2) != 0) { throw new ArgumentException("Invalid length: " + hex.Length); } byte[] ret = new byte[(hex.Length-offset)/2]; for (int i=0; i < ret.Length; i++) { ret[i] = (byte) ((ParseNybble(hex[offset]) << 4) | ParseNybble(hex[offset+1])); offset += 2; } return ret; } static int ParseNybble(char c) { if (c >= '0' && c <= '9') { return c-'0'; } if (c >= 'A' && c <= 'F') { return c-'A'+10; } if (c >= 'a' && c <= 'f') { return c-'a'+10; } throw new ArgumentException("Invalid hex digit: " + c); } } 

(编辑:现在稍微高效 – 不需要子串…)

ParseNybble可能会更有效率。 例如,一个开关/shell可能更有效率:

  static int ParseNybble(char c) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return c-'0'; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return c-'A'+10; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return c-'a'+10; } throw new ArgumentException("Invalid hex digit: " + c); } 

或者可能是一个查找数组:

  // Omitted for brevity... I'm sure you get the gist private static readonly int[] NybbleLookup = BuildLookup(); private int ParseNybble(char c) { if (c > 'f') { throw new ArgumentException("Invalid hex digit: " + c); } int ret = NybbleLookup[c]; if (ret == -1) { throw new ArgumentException("Invalid hex digit: " + c); } return ret; } 

我没有对这些进行基准testing,我也不知道哪个是最快的。 目前的解决scheme可能是最简单的。

考虑利用已经暴露出执行hex转换function的Framework类,例如XmlReader:

 public static byte[] HexToBytes(this string hexEncodedBytes, int start, int end) { int length = end - start; const string tagName = "hex"; string fakeXmlDocument = String.Format("<{1}>{0}</{1}>", hexEncodedBytes.Substring(start, length), tagName); var stream = new MemoryStream(Encoding.ASCII.GetBytes(fakeXmlDocument)); XmlReader reader = XmlReader.Create(stream, new XmlReaderSettings()); int hexLength = length / 2; byte[] result = new byte[hexLength]; reader.ReadStartElement(tagName); reader.ReadContentAsBinHex(result, 0, hexLength); return result; } 

用法:

 string input = "0xBAC893CAB8B7FE03C927417A2A3F6A60BD30FF35E250011CB255"; byte[] bytes = input.HexToBytes(2, input.Length); 

简单:

 string hexnum = "0000000F"; // Represents 15 int value = int.Parse(hexnum, System.Globalization.NumberStyles.HexNumber); 

所有你必须记住要做的是一个整数将hex数字分成8个hex数字组(每个hex4位,CLR inttypes是32位,因此每个int 8位数)。 还有一个byte.Parse()是一样的,但一次只能传入两个hex数字。

像这样的东西:

  public byte[] ParseHexString(string text) { if ((text.Length % 2) != 0) { throw new ArgumentException("Invalid length: " + text.Length); } if (text.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) { text = text.Substring(2); } int arrayLength = text.Length / 2; byte[] byteArray = new byte[arrayLength]; for (int i = 0; i < arrayLength; i++) { byteArray[i] = byte.Parse(text.Substring(i*2, 2), NumberStyles.HexNumber); } return byteArray; } 

你需要稍微修改一下(例如,跳过前两个字符),但是它处理string中的空格:

  /// <summary> /// Decodes a hex string, ignoring all non-hex characters, and stores /// the decodes series of bytes into the shared buffer. This returns /// the number of bytes that were decoded. /// <para>Hex characters are [0-9, af, AF].</para> /// </summary> /// <param name="hexString">String to parse into bytes.</param> /// <param name="buffer">Buffer into which to store the decoded binary data.</param> /// <returns>The number of bytes decoded.</returns> private static int DecodeHexIntoBuffer(string hexString, byte[] buffer) { int count = 0; bool haveFirst = false; bool haveSecond = false; char first = '0'; char second = '0'; for (int i = 0; i < hexString.Length; i++) { if (!haveFirst) { first = hexString[i]; haveFirst = char.IsLetterOrDigit(first); // we have to continue to the next iteration // or we will miss characters continue; } if (!haveSecond) { second = hexString[i]; haveSecond = char.IsLetterOrDigit(second); } if (haveFirst && haveSecond) { string hex = "" + first + second; byte nextByte; if (byte.TryParse(hex, NumberStyles.HexNumber, null, out nextByte)) { // store the decoded byte into the next slot of the buffer buffer[count++] = nextByte; } // reset the flags haveFirst = haveSecond = false; } } return count; } 

慢而有趣的方式:D

 public static byte[] StringToByteArray(string hex) { hex = hex.Replace(" ", ""); hex = hex.Replace(":", ""); return Enumerable.Range(0, hex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) .ToArray(); } 

-JD

实际上,有一种更简单的方法可以将两个字符一次转换为一个字节:

  /// <summary> /// This will convert a hex-encoded string to byte data /// </summary> /// <param name="hexData">The hex-encoded string to convert</param> /// <returns>The bytes that make up the hex string</returns> public static byte[] FromHex(string hexData) { List<byte> data = new List<byte>(); string byteSet = string.Empty; int stringLen = hexData.Length; int length = 0; for (int i = 0; i < stringLen; i = i + 2) { length = (stringLen - i) > 1 ? 2 : 1; byteSet = hexData.Substring(i, length); // try and parse the data data.Add(Convert.ToByte(byteSet, 16 /*base*/)); } // next set return data.ToArray(); } 

我使用这个C#,从Java中的类似的代码。

  private static char[] hexdigit = "0123456789abcdef".ToCharArray(); public static string hexlify(string argbuf) { int arglen = argbuf.Length; char[] argca = argbuf.ToCharArray (); StringBuilder retbuf = new StringBuilder(arglen * 2); for (int i = 0; i < arglen; i++) { char ch = argca[i]; retbuf.Append(hexdigit[(ch >> 4) & 0xF]); retbuf.Append(hexdigit[ch & 0xF]); } return retbuf.ToString(); } public static string unhexlify(string argbuf) { int arglen = argbuf.Length; if (arglen % 2 != 0) { throw new ArgumentOutOfRangeException ("Odd-length string"); } char[] argca = argbuf.ToCharArray (); StringBuilder retbuf = new StringBuilder(arglen / 2); for (int i = 0; i < arglen; i += 2) { int top = Convert.ToInt32 (argca[i].ToString (), 16); int bot = Convert.ToInt32 (argca[i + 1].ToString (), 16); if (top == -1 || bot == -1) { throw new ArgumentOutOfRangeException ("Non-hexadecimal digit found"); } retbuf.Append((char) ((top << 4) + bot)); } return retbuf.ToString(); }