如何将字节数组转换为十六进制字符串,反之亦然?
当前回答
为了方便以后复制和粘贴,将几个答案合并到一个类中:
/// <summary>
/// Extension methods to quickly convert byte array to string and back.
/// </summary>
public static class HexConverter
{
/// <summary>
/// Map values to hex digits
/// </summary>
private static readonly char[] HexDigits =
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
/// <summary>
/// Map 56 characters between ['0', 'F'] to their hex equivalents, and set invalid characters
/// such that they will overflow byte to fail conversion.
/// </summary>
private static readonly ushort[] HexValues =
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x000A, 0x000B,
0x000C, 0x000D, 0x000E, 0x000F
};
/// <summary>
/// Empty byte array
/// </summary>
private static readonly byte[] Empty = new byte[0];
/// <summary>
/// Convert a byte array to a hexadecimal string.
/// </summary>
/// <param name="bytes">
/// The input byte array.
/// </param>
/// <returns>
/// A string of hexadecimal digits.
/// </returns>
public static string ToHexString(this byte[] bytes)
{
var c = new char[bytes.Length * 2];
for (int i = 0, j = 0; i < bytes.Length; i++)
{
c[j++] = HexDigits[bytes[i] >> 4];
c[j++] = HexDigits[bytes[i] & 0x0F];
}
return new string(c);
}
/// <summary>
/// Parse a string of hexadecimal digits into a byte array.
/// </summary>
/// <param name="hexadecimalString">
/// The hexadecimal string.
/// </param>
/// <returns>
/// The parsed <see cref="byte[]"/> array.
/// </returns>
/// <exception cref="ArgumentException">
/// The input string either contained invalid characters, or was of an odd length.
/// </exception>
public static byte[] ToByteArray(string hexadecimalString)
{
if (!TryParse(hexadecimalString, out var value))
{
throw new ArgumentException("Invalid hexadecimal string", nameof(hexadecimalString));
}
return value;
}
/// <summary>
/// Parse a hexadecimal string to bytes
/// </summary>
/// <param name="hexadecimalString">
/// The hexadecimal string, which must be an even number of characters.
/// </param>
/// <param name="value">
/// The parsed value if successful.
/// </param>
/// <returns>
/// True if successful.
/// </returns>
public static bool TryParse(string hexadecimalString, out byte[] value)
{
if (hexadecimalString.Length == 0)
{
value = Empty;
return true;
}
if (hexadecimalString.Length % 2 != 0)
{
value = Empty;
return false;
}
try
{
value = new byte[hexadecimalString.Length / 2];
for (int i = 0, j = 0; j < hexadecimalString.Length; i++)
{
value[i] = (byte)((HexValues[hexadecimalString[j++] - '0'] << 4)
| HexValues[hexadecimalString[j++] - '0']);
}
return true;
}
catch (OverflowException)
{
value = Empty;
return false;
}
}
}
其他回答
扩展方法(免责声明:完全未经测试的代码,BTW…):
public static class ByteExtensions
{
public static string ToHexString(this byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
hex.AppendFormat("{0:x2}", b);
}
return hex.ToString();
}
}
使用Tomalak的三种解决方案之一(最后一种是字符串上的扩展方法)。
在编写加密代码时,通常避免依赖数据的分支和表查找,以确保运行时不依赖于数据,因为依赖数据的计时可能会导致侧通道攻击。
它也很快。
static string ByteToHexBitFiddle(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
int b;
for (int i = 0; i < bytes.Length; i++) {
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b-10)>>31)&-7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b-10)>>31)&-7));
}
return new string(c);
}
Ph'nglui mglw'naph Cthulhu R'lieh wgah'nagl fhtagn公司
你们这些进入这里的人,放弃一切希望吧
一个奇怪的拨弄解释:
bytes[i]>>4提取字节的高位半字节bytes[i]&0xF提取字节的低位半字节b-10对于值b<10,为<0,将变为十进制数字对于值b>10,为>=0,这将成为从a到F的字母。在有符号32位整数上使用i>>31可以提取符号,这得益于符号扩展。当i<0时为-1,当i>=0时为0。结合2)和3),表明(b-10)>>31将是字母0,数字-1。看看字母的大小写,最后一个被加数变为0,b在10到15的范围内。我们希望将其映射到A(65)到F(70),这意味着添加55('A'-10)。看看数字的情况,我们希望调整最后一个被加数,使其将b从范围0到9映射到范围0(48)到9(57)。这意味着它需要变为-7('0'-55)。现在我们可以乘以7。但由于-1由所有位表示为1,因此我们可以改用&-7,因为(0&-7)==0和(-1&-7)==-7。
进一步考虑:
我没有使用第二个循环变量来索引c,因为测量表明从I计算它更便宜。正好使用i<bytes.Length作为循环的上限允许JITter消除对bytes[i]的边界检查,所以我选择了这个变量。将b设为int允许不必要的从和到字节的转换。
就速度而言,这似乎比这里的任何东西都要好:
public static string ToHexString(byte[] data) {
byte b;
int i, j, k;
int l = data.Length;
char[] r = new char[l * 2];
for (i = 0, j = 0; i < l; ++i) {
b = data[i];
k = b >> 4;
r[j++] = (char)(k > 9 ? k + 0x37 : k + 0x30);
k = b & 15;
r[j++] = (char)(k > 9 ? k + 0x37 : k + 0x30);
}
return new string(r);
}
另一种方法是使用stackaloc来降低GC内存压力:
static string ByteToHexBitFiddle(byte[] bytes)
{
var c = stackalloc char[bytes.Length * 2 + 1];
int b;
for (int i = 0; i < bytes.Length; ++i)
{
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
}
c[bytes.Length * 2 ] = '\0';
return new string(c);
}
具有扩展支持的基本解决方案
public static class Utils
{
public static byte[] ToBin(this 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;
}
public static string ToHex(this byte[] ba)
{
return BitConverter.ToString(ba).Replace("-", "");
}
}
并像下面那样使用这个类
byte[] arr1 = new byte[] { 1, 2, 3 };
string hex1 = arr1.ToHex();
byte[] arr2 = hex1.ToBin();
推荐文章
- HTTP POST返回错误:417“期望失败。”
- 如何在。net中创建和使用资源
- 为什么Path。以Path.DirectorySeparatorChar开头的文件名合并不正确?
- 如何在c#中获得正确的时间戳
- 如何读一个文本文件到一个列表或数组与Python
- Linq选择列表中存在的对象(A,B,C)
- c# .NET中的App.config是什么?如何使用它?
- 如何在Python中将十六进制字符串转换为字节?
- c#:如何获得一个字符串的第一个字符?
- String类中的什么方法只返回前N个字符?
- 更好的方法将对象转换为int类型
- 我可以将c#字符串值转换为转义字符串文字吗?
- 在c#中转换char到int
- c#中朋友的对等物是什么?
- 关键字使用virtual+override vs. new