如何将字节数组转换为十六进制字符串,反之亦然?
当前回答
这是我的尝试。我创建了一对扩展类来扩展字符串和字节。在大文件测试中,性能与Byte Manipulation 2相当。
下面的ToHexString代码是查找和移位算法的优化实现。它与Behrooz的方法几乎相同,但使用foreach进行迭代,计数器比显式索引更快。
在我的机器上,它排在Byte Manipulation 2之后,排在第二位,是非常可读的代码。以下测试结果也值得关注:
ToHexStringCharArrayWithCharArrayLookup:41589.69平均刻度(超过1000次),1.5倍ToHexStringCharArrayWithStringLookup:50764.06平均滴答(超过1000次),1.2XToHexStringStringBuilderWithCharArrayLookup:62812.87平均滴答(超过1000次),1.0X
根据上述结果,可以得出以下结论:
索引到字符串以执行查找与char数组在大型文件测试中非常重要。使用已知容量的StringBuilder与使用字符的惩罚创建字符串的已知大小的数组甚至更重要。
代码如下:
using System;
namespace ConversionExtensions
{
public static class ByteArrayExtensions
{
private readonly static char[] digits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static string ToHexString(this byte[] bytes)
{
char[] hex = new char[bytes.Length * 2];
int index = 0;
foreach (byte b in bytes)
{
hex[index++] = digits[b >> 4];
hex[index++] = digits[b & 0x0F];
}
return new string(hex);
}
}
}
using System;
using System.IO;
namespace ConversionExtensions
{
public static class StringExtensions
{
public static byte[] ToBytes(this string hexString)
{
if (!string.IsNullOrEmpty(hexString) && hexString.Length % 2 != 0)
{
throw new FormatException("Hexadecimal string must not be empty and must contain an even number of digits to be valid.");
}
hexString = hexString.ToUpperInvariant();
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < hexString.Length; index += 2)
{
int highDigitValue = hexString[index] <= '9' ? hexString[index] - '0' : hexString[index] - 'A' + 10;
int lowDigitValue = hexString[index + 1] <= '9' ? hexString[index + 1] - '0' : hexString[index + 1] - 'A' + 10;
if (highDigitValue < 0 || lowDigitValue < 0 || highDigitValue > 15 || lowDigitValue > 15)
{
throw new FormatException("An invalid digit was encountered. Valid hexadecimal digits are 0-9 and A-F.");
}
else
{
byte value = (byte)((highDigitValue << 4) | (lowDigitValue & 0x0F));
data[index / 2] = value;
}
}
return data;
}
}
}
下面是当我将代码放在我机器上的@patridge测试项目中时得到的测试结果。我还添加了一个从十六进制转换为字节数组的测试。使用我的代码的测试运行是ByteArrayToHexViaOptimizedLookupAndShift和HexToByteArrayViaByteManipulation。HexToByteArrayViaConvertToByte取自XXXX。HexToByteArrayViaSoapHexBinary是@Mykroft的答案。
Intel Pentium III Xeon处理器核心:4<br/>当前时钟速度:1576<br/>最大时钟速度:3092<br/>将字节数组转换为十六进制字符串表示ByteArrayToHexViaByteManipulation2:39366.64平均滴答(超过1000次),22.4倍ByteArrayToHexViaOptimizedLookupAndShift:41588.64平均刻度(超过1000次),21.2倍ByteArrayToHexViaLookup:55509.56次平均点击(超过1000次),15.9倍ByteArrayToHexViaByteManipulation:65349.12平均刻度(超过1000次),13.5XByteArrayToHexViaLookupAndShift:86926.87平均刻度(超过1000运行),10.2XByteArrayToHexStringViaBitConverter:平均139353.73滴答声(超过1000次),6.3XByteArrayToHexViaSoapHexBinary:314598.77平均刻度(超过1000次),2.8XByteArrayToHexStringViaStringBuilderForEachByteToString:344264.63平均刻度(超过1000次),2.6XByteArrayToHexStringViaStringBuilderAggregateByteToString:382623.44平均滴答声(超过1000次),2.3XByteArrayToHexStringViaStringBuilderForEachAppend格式:818111.95平均滴答声(超过1000次),1.1倍ByteArrayToHexStringViaStringConcatArray ConvertAll:839424.84平均值滴答声(超过1000次),1.1XByteArrayToHexStringViaStringBuilderAggregateAppend格式:867303.98平均刻度(超过1000次),1.0XByteArrayToHexStringViaStringJoinArray ConvertAll:平均882710.28滴答声(超过1000次),1.0X
其他回答
在编写加密代码时,通常避免依赖数据的分支和表查找,以确保运行时不依赖于数据,因为依赖数据的计时可能会导致侧通道攻击。
它也很快。
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允许不必要的从和到字节的转换。
此版本的ByteArrayToHexViaByteManipulation可能更快。
从我的报告中:
ByteArrayToHexViaByteManipulation3:1.68次平均滴答声(超过1000次),17,5XByteArrayToHexViaByteManipulation2:1,73平均滴答(超过1000次),16,9XByteArrayToHexViaByteManipulation:2,90平均刻度(超过1000次),10,1XByteArrayToHexViaLookupAndShift:3.22平均刻度(超过1000次),9,1X...静态专用只读字符[]hexAlphabet=新字符[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};静态字符串ByteArrayToHexViaByteManipulation3(byte[]字节){char[]c=新字符[bytes.Length*2];字节b;for(int i=0;i<bytes.Length;i++){b=((字节)(字节[i]>>4));c[i*2]=十六进制字母[b];b=((字节)(字节[i]&0xF));c[i*2+1]=十六进制字母[b];}返回新字符串(c);}
我认为这是一个优化:
static private readonly char[] hexAlphabet = new char[]
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
static string ByteArrayToHexViaByteManipulation4(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
for (int i = 0, ptr = 0; i < bytes.Length; i++, ptr += 2)
{
byte b = bytes[i];
c[ptr] = hexAlphabet[b >> 4];
c[ptr + 1] = hexAlphabet[b & 0xF];
}
return new string(c);
}
Waleed Eissa代码的逆函数(十六进制字符串到字节数组):
public static byte[] HexToBytes(this string hexString)
{
byte[] b = new byte[hexString.Length / 2];
char c;
for (int i = 0; i < hexString.Length / 2; i++)
{
c = hexString[i * 2];
b[i] = (byte)((c < 0x40 ? c - 0x30 : (c < 0x47 ? c - 0x37 : c - 0x57)) << 4);
c = hexString[i * 2 + 1];
b[i] += (byte)(c < 0x40 ? c - 0x30 : (c < 0x47 ? c - 0x37 : c - 0x57));
}
return b;
}
Waleed Eissa功能,支持小写:
public static string BytesToHex(this byte[] barray, bool toLowerCase = true)
{
byte addByte = 0x37;
if (toLowerCase) addByte = 0x57;
char[] c = new char[barray.Length * 2];
byte b;
for (int i = 0; i < barray.Length; ++i)
{
b = ((byte)(barray[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + addByte : b + 0x30);
b = ((byte)(barray[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + addByte : b + 0x30);
}
return new string(c);
}
有一个名为SoapHexBinary的类,它完全符合您的需要。
using System.Runtime.Remoting.Metadata.W3cXsd2001;
public static byte[] GetStringToBytes(string value)
{
SoapHexBinary shb = SoapHexBinary.Parse(value);
return shb.Value;
}
public static string GetBytesToString(byte[] value)
{
SoapHexBinary shb = new SoapHexBinary(value);
return shb.ToString();
}
Dotnet 5更新
要从byte[](字节数组)转换为十六进制字符串,请使用:
System.Convert.ToHexString
var myBytes = new byte[100];
var myString = System.Convert.ToHexString(myBytes);
要将十六进制字符串转换为字节[],请使用:
System.Convert.FromHexString
var myString = "E10B116E8530A340BCC7B3EAC208487B";
var myBytes = System.Convert.FromHexString(myString);
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- 使用C返回一个数组
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 向对象数组添加属性
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>