如何将字节数组转换为十六进制字符串,反之亦然?


当前回答

如果你想得到wcoenen报告的“4倍速度增长”,那么如果不明显:用hex[i]+hex[i+1]替换hex.Substring(i,2)

您还可以再进一步,通过在两个地方使用i++来消除i+=2。

其他回答

我今天遇到了同样的问题,我遇到了以下代码:

private static string ByteArrayToHex(byte[] barray)
{
    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 + 0x37 : b + 0x30);
        b = ((byte)(barray[i] & 0xF));
        c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
    }
    return new string(c);
}

来源:论坛帖子byte[]数组到十六进制字符串(见PZahra的帖子)。我稍微修改了一下代码,删除了0x前缀。

我对代码进行了一些性能测试,它几乎比使用BitConverter.ToString()快八倍(根据patridge的帖子,速度最快)。

多样性的另一种变化:

public static byte[] FromHexString(string src)
{
    if (String.IsNullOrEmpty(src))
        return null;

    int index = src.Length;
    int sz = index / 2;
    if (sz <= 0)
        return null;

    byte[] rc = new byte[sz];

    while (--sz >= 0)
    {
        char lo = src[--index];
        char hi = src[--index];

        rc[sz] = (byte)(
            (
                (hi >= '0' && hi <= '9') ? hi - '0' :
                (hi >= 'a' && hi <= 'f') ? hi - 'a' + 10 :
                (hi >= 'A' && hi <= 'F') ? hi - 'A' + 10 :
                0
            )
            << 4 | 
            (
                (lo >= '0' && lo <= '9') ? lo - '0' :
                (lo >= 'a' && lo <= 'f') ? lo - 'a' + 10 :
                (lo >= 'A' && lo <= 'F') ? lo - 'A' + 10 :
                0
            )
        );
    }

    return rc;          
}

支持最短路径和.net核心:

    public static string BytesToString(byte[] ba) =>
        ba.Aggregate(new StringBuilder(32), (sb, b) => sb.Append(b.ToString("X2"))).ToString();

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);
    }

这是我的尝试。我创建了一对扩展类来扩展字符串和字节。在大文件测试中,性能与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