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


当前回答

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

其他回答

这是一篇很棒的帖子。我喜欢瓦利德的解决方案。我还没有通过帕特里奇的测试,但似乎很快。我还需要反向过程,将十六进制字符串转换为字节数组,因此我将其作为Waleed解决方案的反向来编写。不确定它是否比托马拉克的原始解决方案更快。同样,我也没有通过帕特里奇的测试运行相反的过程。

private byte[] HexStringToByteArray(string hexString)
{
    int hexStringLength = hexString.Length;
    byte[] b = new byte[hexStringLength / 2];
    for (int i = 0; i < hexStringLength; i += 2)
    {
        int topChar = (hexString[i] > 0x40 ? hexString[i] - 0x37 : hexString[i] - 0x30) << 4;
        int bottomChar = hexString[i + 1] > 0x40 ? hexString[i + 1] - 0x37 : hexString[i + 1] - 0x30;
        b[i / 2] = Convert.ToByte(topChar + bottomChar);
    }
    return b;
}

我想出了一个不同的代码,它可以容忍额外的字符(空格、破折号…)。它的灵感主要来自这里一些可以接受的快速答案。它允许解析以下“文件”

00-aa-84-fb
12 32 FF CD
12 00
12_32_FF_CD
1200d5e68a
/// <summary>Reads a hex string into bytes</summary>
public static IEnumerable<byte> HexadecimalStringToBytes(string hex) {
    if (hex == null)
        throw new ArgumentNullException(nameof(hex));

    char c, c1 = default(char);
    bool hasc1 = false;
    unchecked   {
        for (int i = 0; i < hex.Length; i++) {
            c = hex[i];
            bool isValid = 'A' <= c && c <= 'f' || 'a' <= c && c <= 'f' || '0' <= c && c <= '9';
            if (!hasc1) {
                if (isValid) {
                    hasc1 = true;
                }
            } else {
                hasc1 = false;
                if (isValid) {
                    yield return (byte)((GetHexVal(c1) << 4) + GetHexVal(c));
                }
            }

            c1 = c;
        } 
    }
}

/// <summary>Reads a hex string into a byte array</summary>
public static byte[] HexadecimalStringToByteArray(string hex)
{
    if (hex == null)
        throw new ArgumentNullException(nameof(hex));

    var bytes = new List<byte>(hex.Length / 2);
    foreach (var item in HexadecimalStringToBytes(hex)) {
        bytes.Add(item);
    }

    return bytes.ToArray();
}

private static byte GetHexVal(char val)
{
    return (byte)(val - (val < 0x3A ? 0x30 : val < 0x5B ? 0x37 : 0x57));
    //                   ^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^   ^^^^
    //                       digits 0-9       upper char A-Z     a-z
}

复制时请参考完整代码。包括单元测试。

有些人可能会说它对额外的字符太宽容了。因此,不要依赖此代码来执行验证(或更改)。

对于Java 8,我们可以使用Byte.toUnsignedInt

public static String convertBytesToHex(byte[] bytes) {
    StringBuilder result = new StringBuilder();
    for (byte byt : bytes) {
        int decimal = Byte.toUnsignedInt(byt);
        String hex = Integer.toHexString(decimal);
        result.append(hex);
    }
    return result.toString();
}

具有扩展支持的基本解决方案

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

如果性能很重要,这里有一个优化的解决方案:

    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倍。