如何将字节数组转换为十六进制字符串,反之亦然?
当前回答
static string ByteArrayToHexViaLookupPerByte2(byte[] bytes)
{
var result3 = new uint[bytes.Length];
for (int i = 0; i < bytes.Length; i++)
result3[i] = _Lookup32[bytes[i]];
var handle = GCHandle.Alloc(result3, GCHandleType.Pinned);
try
{
var result = Marshal.PtrToStringUni(handle.AddrOfPinnedObject(), bytes.Length * 2);
return result;
}
finally
{
handle.Free();
}
}
在我的测试中,这个函数总是不安全实现之后的第二个条目。
不幸的是,测试台不太可靠。。。如果你多次运行它,列表会被打乱,以至于谁知道在不安全之后哪个才是最快的!它没有考虑预热、jit编译时间和GC性能影响。我很想重写它以获得更多信息,但我真的没有时间。
其他回答
为什么要让它变得复杂?这在Visual Studio 2008中很简单:
C#:
string hex = BitConverter.ToString(YourByteArray).Replace("-", "");
VB:
Dim hex As String = BitConverter.ToString(YourByteArray).Replace("-", "")
如果性能很重要,这里有一个优化的解决方案:
static readonly char[] _hexDigits = "0123456789abcdef".ToCharArray();
public static string ToHexString(this byte[] bytes)
{
char[] digits = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
int d1, d2;
d1 = Math.DivRem(bytes[i], 16, out d2);
digits[2 * i] = _hexDigits[d1];
digits[2 * i + 1] = _hexDigits[d2];
}
return new string(digits);
}
它比BitConverter.ToString快2.5倍,比BitConverter.ToString+删除“-”字符快7倍。
下面还通过允许本机小写选项扩展了这里的优秀答案,并且还处理null或空输入,并使其成为扩展方法。
/// <summary>
/// Converts the byte array to a hex string very fast. Excellent job
/// with code lightly adapted from 'community wiki' here: https://stackoverflow.com/a/14333437/264031
/// (the function was originally named: ByteToHexBitFiddle). Now allows a native lowerCase option
/// to be input and allows null or empty inputs (null returns null, empty returns empty).
/// </summary>
public static string ToHexString(this byte[] bytes, bool lowerCase = false)
{
if (bytes == null)
return null;
else if (bytes.Length == 0)
return "";
char[] c = new char[bytes.Length * 2];
int b;
int xAddToAlpha = lowerCase ? 87 : 55;
int xAddToDigit = lowerCase ? -39 : -7;
for (int i = 0; i < bytes.Length; i++) {
b = bytes[i] >> 4;
c[i * 2] = (char)(xAddToAlpha + b + (((b - 10) >> 31) & xAddToDigit));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(xAddToAlpha + b + (((b - 10) >> 31) & xAddToDigit));
}
string val = new string(c);
return val;
}
public static string ToHexString(this IEnumerable<byte> bytes, bool lowerCase = false)
{
if (bytes == null)
return null;
byte[] arr = bytes.ToArray();
return arr.ToHexString(lowerCase);
}
可以使用从.NET 5开始的Convert.ToHexString。还有一个用于反向操作的方法:Convert.FromHexString。
对于较旧版本的.NET,您可以使用:
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
or:
public static string ByteArrayToString(byte[] ba)
{
return BitConverter.ToString(ba).Replace("-","");
}
举个例子,这里有更多的方法。
反向转换如下:
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
使用Substring是与Convert.ToByte结合使用的最佳选项。有关详细信息,请参阅此答案。如果需要更好的性能,必须避免Convert.ToByte,然后才能删除SubString。
这里不想赘述很多答案,但我发现了一个十六进制字符串解析器的相当优化(比公认的好4.5倍)、简单的实现。首先,我的测试输出(第一批是我的实现):
Give me that string:
04c63f7842740c77e545bb0b2ade90b384f119f6ab57b680b7aa575a2f40939f
Time to parse 100,000 times: 50.4192 ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
Accepted answer: (StringToByteArray)
Time to parse 100000 times: 233.1264ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
With Mono's implementation:
Time to parse 100000 times: 777.2544ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
With SoapHexBinary:
Time to parse 100000 times: 845.1456ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
base64和“BitConverter'd”行用于测试正确性。请注意,它们是相等的。
实施:
public static byte[] ToByteArrayFromHex(string hexString)
{
if (hexString.Length % 2 != 0) throw new ArgumentException("String must have an even length");
var array = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length; i += 2)
{
array[i/2] = ByteFromTwoChars(hexString[i], hexString[i + 1]);
}
return array;
}
private static byte ByteFromTwoChars(char p, char p_2)
{
byte ret;
if (p <= '9' && p >= '0')
{
ret = (byte) ((p - '0') << 4);
}
else if (p <= 'f' && p >= 'a')
{
ret = (byte) ((p - 'a' + 10) << 4);
}
else if (p <= 'F' && p >= 'A')
{
ret = (byte) ((p - 'A' + 10) << 4);
} else throw new ArgumentException("Char is not a hex digit: " + p,"p");
if (p_2 <= '9' && p_2 >= '0')
{
ret |= (byte) ((p_2 - '0'));
}
else if (p_2 <= 'f' && p_2 >= 'a')
{
ret |= (byte) ((p_2 - 'a' + 10));
}
else if (p_2 <= 'F' && p_2 >= 'A')
{
ret |= (byte) ((p_2 - 'A' + 10));
} else throw new ArgumentException("Char is not a hex digit: " + p_2, "p_2");
return ret;
}
我尝试了一些不安全的东西,并将(显然是冗余的)字符移动到另一个方法来蚕食if序列,但这是最快的。
(我承认这回答了一半的问题。我觉得字符串->字节[]转换不足,而字节[]->字符串角度似乎被很好地覆盖了。因此,这个答案。)
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- 使用C返回一个数组
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 向对象数组添加属性
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>