如何将十六进制字符串转换为字节数组?

342

在C#中,我们是否可以使用内置函数将十六进制字符串转换为字节数组,还是需要编写自定义方法来完成此操作?


2
你可以轻松地将字符串转换为字节数组,只需一行代码:var byteArray = Encoding.ASCII.GetBytes(string_with_your_data); - mikhail-t
35
@mik-T,一个十六进制字符串的格式类似于219098C10D7,其中每两个字符转换为一个字节。你的方法是不可用的。 - AaA
5
这个问题似乎不是所选问题的副本。 这个问题将从十六进制字符串转换为字节数组,而另一个问题则将字节数组转换为十六进制。 - AaA
3
一个简单的一行代码:BigInteger.Parse(str, System.Globalization.NumberStyles.HexNumber).ToByteArray().Reverse().ToArray() - Gregory Morse
@GregoryMorse 注意,BigInteger假定字符串表示为有符号数字,并且如果MSB的最高有效位为1,则会给出意外结果,除非您进行特殊处理。 - Oskar Berggren
在解析之前,是的,你应该在字符串前面加上“00”。你说得没错,那段代码只有50%的准确率。"00" + str - Gregory Morse
4个回答

596

这里有一个不错的有趣的LINQ示例。

public static byte[] StringToByteArray(string hex) {
    return Enumerable.Range(0, hex.Length)
                     .Where(x => x % 2 == 0)
                     .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                     .ToArray();
}

214
天哪!!你意识到这是多么低效吗??当然,这很有趣,但LINQ被过度使用于本可以用其他方式解决的事情上!LINQ代码需要.NET 3.5并需要引用System.Core(否则可能不需要)。请参阅重复的文章以获得高效的解决方案。 - Kevin P. Rice
43
可能只是为了好玩,而不是为了效率。 - Karsten
32
LINQ 的优雅和多功能性令人印象深刻。 - Michael Richardson
6
为了反向转换,我想到了这个方法。如果其他人也需要的话...公共静态字符串ByteArrayToBinHex(此字节数组[]字节) { 返回字节.Select(b => b.ToString("X2")).Aggregate((s1, s2) => s1 + s2); } - dviljoen
49
简化版为:Enumerable.Range(0, hex.Length / 2) .Select(x => Convert.ToByte(hex.Substring(x * 2, 2), 16)) .ToArray()。该代码将一个十六进制字符串转换为字节数组。 - Hossein Shahdoost
显示剩余13条评论

114

我进行了一些研究并发现byte.Parse比Convert.ToByte甚至更慢。 我能够想到的最快转换速度大约为每字节15个刻度。

    public static byte[] StringToByteArrayFastest(string hex) {
        if (hex.Length % 2 == 1)
            throw new Exception("The binary key cannot have an odd number of digits");

        byte[] arr = new byte[hex.Length >> 1];

        for (int i = 0; i < hex.Length >> 1; ++i)
        {
            arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
        }

        return arr;
    }

    public static int GetHexVal(char hex) {
        int val = (int)hex;
        //For uppercase A-F letters:
        //return val - (val < 58 ? 48 : 55);
        //For lowercase a-f letters:
        //return val - (val < 58 ? 48 : 87);
        //Or the two combined, but a bit slower:
        return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
    }

// 该方法在.NET Micro Framework中也能正常工作,因为在SDK4.3中,byte.Parse(string)仅支持整数格式。


2
要回答这个问题,你需要了解编译器如何决定自动内联的许多细节。 - John Nicholas
2
字节与十六进制字符在我的端上顺序相同。你说的“反转”是什么意思? - bytefire
2
为什么要将hex.Length向右移动一位? hex.Length >> 1 - Mohammad Hossein Amri
9
我刚发现这段代码被粘贴到了我要维护的程序中。它不再编译并抛出一个CS0307错误(变量“i”不能与类型参数一起使用),以及一个CS0118错误(“hex”是一个变量但被用作类型)。使用位移操作(而不是简单的“/2”)可能看起来很酷,但对于99.99%的开发人员来说,这是一个明显的过早优化问题。 - StingyJack
3
@RobertSnyder - 我的观点并不是关于编译(尽管它在没有最近更改构建服务器的情况下一夜之间出了问题)。我们有一个顾问将这段代码复制粘贴到一个不需要这种性能水平的程序中。 - StingyJack
显示剩余16条评论

63

以下代码通过逐个解析字符串字节,将十六进制字符串更改为字节数组。

public static byte[] ConvertHexStringToByteArray(string hexString)
{
    if (hexString.Length % 2 != 0)
    {
        throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hexString));
    }

    byte[] data = new byte[hexString.Length / 2];
    for (int index = 0; index < data.Length; index++)
    {
        string byteValue = hexString.Substring(index * 2, 2);
        data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
    }

    return data; 
}

难道不应该是 "for (int index = 0; index < HexAsBytes.Length; index++)" 吗? - Noli
68016101061B4A60193390662046804020422044204000420040402060226024676DB16 with this i am getting The binary key cannot have an odd number of digits - Moeez
1
@Moeez 你看了你的输入和收到的信息吗? - Dominik Szymański

13

我认为这可能有效。

public static byte[] StrToByteArray(string str)
    {
        Dictionary<string, byte> hexindex = new Dictionary<string, byte>();
        for (int i = 0; i <= 255; i++)
            hexindex.Add(i.ToString("X2"), (byte)i);

        List<byte> hexres = new List<byte>();
        for (int i = 0; i < str.Length; i += 2)            
            hexres.Add(hexindex[str.Substring(i, 2)]);

        return hexres.ToArray();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接