如何将字节数组转换为十六进制字符串,反之亦然?
当前回答
用@CodesInChaus补充答案(反向方法)
public static byte[] HexToByteUsingByteManipulation(string s)
{
byte[] bytes = new byte[s.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
int hi = s[i*2] - 65;
hi = hi + 10 + ((hi >> 31) & 7);
int lo = s[i*2 + 1] - 65;
lo = lo + 10 + ((lo >> 31) & 7) & 0x0f;
bytes[i] = (byte) (lo | hi << 4);
}
return bytes;
}
说明:
&0x0f还支持小写字母
hi=hi+10+((hi>>31)&7);与以下内容相同:
hi=ch-65+10+((ch-65)>>31)&7);
对于“0”9’与hi=ch-65+10+7相同;其为hi=ch-48(这是因为0xffffff&7)。
对于“A”F’为hi=ch-65+10;(这是因为0x00000000&7)。
对于“a”我们必须使用大数字,所以我们必须通过使用&0x0f使某些位为0,从默认版本中减去32。
65是“A”的代码
48是“0”的代码
7是ASCII表中“9”和“A”之间的字母数(…456789:;<=>?@ABCD…)。
其他回答
您可以使用BitConverter.ToString方法:
byte[] bytes = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256}
Console.WriteLine( BitConverter.ToString(bytes));
输出:
00-01-02-04-08-10-20-40-80-FF
更多信息:BitConverter.ToString方法(Byte[])
用@CodesInChaus补充答案(反向方法)
public static byte[] HexToByteUsingByteManipulation(string s)
{
byte[] bytes = new byte[s.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
int hi = s[i*2] - 65;
hi = hi + 10 + ((hi >> 31) & 7);
int lo = s[i*2 + 1] - 65;
lo = lo + 10 + ((lo >> 31) & 7) & 0x0f;
bytes[i] = (byte) (lo | hi << 4);
}
return bytes;
}
说明:
&0x0f还支持小写字母
hi=hi+10+((hi>>31)&7);与以下内容相同:
hi=ch-65+10+((ch-65)>>31)&7);
对于“0”9’与hi=ch-65+10+7相同;其为hi=ch-48(这是因为0xffffff&7)。
对于“A”F’为hi=ch-65+10;(这是因为0x00000000&7)。
对于“a”我们必须使用大数字,所以我们必须通过使用&0x0f使某些位为0,从默认版本中减去32。
65是“A”的代码
48是“0”的代码
7是ASCII表中“9”和“A”之间的字母数(…456789:;<=>?@ABCD…)。
下面还通过允许本机小写选项扩展了这里的优秀答案,并且还处理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);
}
有一个简单的一行解决方案尚未提及,它将十六进制字符串转换为字节数组(我们不在乎这里的否定解释,因为这无关紧要):
BigInteger.Parse(str, System.Globalization.NumberStyles.HexNumber).ToByteArray().Reverse().ToArray();
这个问题也可以使用查找表来解决。这将需要编码器和解码器的少量静态存储器。然而,这种方法很快:
编码器表512字节或1024字节(两次大小写(如果是大写和小写)需要)解码器表256字节或64 KiB(单个字符查找或双字符查找)
我的解决方案使用1024字节作为编码表,256字节用于解码。
解码
private static readonly byte[] LookupTable = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static byte Lookup(char c)
{
var b = LookupTable[c];
if (b == 255)
throw new IOException("Expected a hex character, got " + c);
return b;
}
public static byte ToByte(char[] chars, int offset)
{
return (byte)(Lookup(chars[offset]) << 4 | Lookup(chars[offset + 1]));
}
编码
private static readonly char[][] LookupTableUpper;
private static readonly char[][] LookupTableLower;
static Hex()
{
LookupTableLower = new char[256][];
LookupTableUpper = new char[256][];
for (var i = 0; i < 256; i++)
{
LookupTableLower[i] = i.ToString("x2").ToCharArray();
LookupTableUpper[i] = i.ToString("X2").ToCharArray();
}
}
public static char[] ToCharLower(byte[] b, int bOffset)
{
return LookupTableLower[b[bOffset]];
}
public static char[] ToCharUpper(byte[] b, int bOffset)
{
return LookupTableUpper[b[bOffset]];
}
比较
StringBuilderToStringFromBytes: 106148
BitConverterToStringFromBytes: 15783
ArrayConvertAllToStringFromBytes: 54290
ByteManipulationToCharArray: 8444
TableBasedToCharArray: 5651 *
*这个解决方案
Note
在解码过程中,可能会发生IOException和IndexOutOfRangeException(如果字符的值太高>256)。应该实现对流或数组进行去/编码的方法,这只是概念的证明。
推荐文章
- 在JavaScript中根据键值查找和删除数组中的对象
- 防止在ASP中缓存。NET MVC中使用属性的特定操作
- 如何确定一个数组是否包含另一个数组的所有元素
- 转换为值类型'Int32'失败,因为物化值为空
- c#中有任何连接字符串解析器吗?
- 给定一个数字数组,返回所有其他数字的乘积的数组(不除法)
- 多维数组如何在内存中格式化?
- 在Linq中转换int到字符串到实体的问题
- 是否可以动态编译和执行c#代码片段?
- 创建自定义MSBuild任务时,如何从c#代码获取当前项目目录?
- c#和Java的主要区别是什么?
- 在c#中创建一个特定时区的DateTime
- .NET中的属性是什么?
- TypeScript枚举对象数组
- csproj文件中的“Service Include”是干什么用的?