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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/311165/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:42:12  来源:igfitidea点击:

How do you convert a byte array to a hexadecimal string, and vice versa?

c#arrayshex

提问by alextansc

How can you convert a byte array to a hexadecimal string, and vice versa?

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

采纳答案by Tomalak

Either:

任何一个:

public static string ByteArrayToString(byte[] ba)
{
  StringBuilder hex = new StringBuilder(ba.Length * 2);
  foreach (byte b in ba)
    hex.AppendFormat("{0:x2}", b);
  return hex.ToString();
}

or:

或者:

public static string ByteArrayToString(byte[] ba)
{
  return BitConverter.ToString(ba).Replace("-","");
}

There are even more variants of doing it, for example here.

这样做还有更多变体,例如这里

The reverse conversion would go like this:

反向转换将是这样的:

public static byte[] StringToByteArray(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;
}


Using Substringis the best option in combination with Convert.ToByte. See this answerfor more information. If you need better performance, you must avoid Convert.ToBytebefore you can drop SubString.

结合使用Substring是最好的选择Convert.ToByte。有关更多信息,请参阅此答案。如果您需要更好的性能,则必须避免Convert.ToByte才能删除SubString.

回答by Pure.Krome

Extension methods(disclaimer: completely untested code, BTW...):

扩展方法(免责声明:完全未经测试的代码,顺便说一句......):

public static class ByteExtensions
{
    public static string ToHexString(this byte[] ba)
    {
        StringBuilder hex = new StringBuilder(ba.Length * 2);

        foreach (byte b in ba)
        {
            hex.AppendFormat("{0:x2}", b);
        }
        return hex.ToString();
    }
}

etc.. Use either of Tomalak's three solutions(with the last one being an extension method on a string).

等.. 使用Tomalak 的三种解决方案之一(最后一种是字符串上的扩展方法)。

回答by Baget

You can use the BitConverter.ToString method:

您可以使用 BitConverter.ToString 方法:

byte[] bytes = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256}
Console.WriteLine( BitConverter.ToString(bytes));

Output:

输出:

00-01-02-04-08-10-20-40-80-FF

00-01-02-04-08-10-20-40-80-FF

More information: BitConverter.ToString Method (Byte[])

更多信息:BitConverter.ToString 方法 (Byte[])

回答by Will Dean

If you want more flexibility than BitConverter, but don't want those clunky 1990s-style explicit loops, then you can do:

如果您想要比 更大的灵活性BitConverter,但不想要那些笨拙的 1990 年代风格的显式循环,那么您可以这样做:

String.Join(String.Empty, Array.ConvertAll(bytes, x => x.ToString("X2")));

Or, if you're using .NET 4.0:

或者,如果您使用的是 .NET 4.0:

String.Concat(Array.ConvertAll(bytes, x => x.ToString("X2")));

(The latter from a comment on the original post.)

(后者来自对原始帖子的评论。)

回答by patridge

Performance Analysis

性能分析

Note: new leader as of 2015-08-20.

注:截至 2015-08-20 的新领导人。

I ran each of the various conversion methods through some crude Stopwatchperformance testing, a run with a random sentence (n=61, 1000 iterations) and a run with a Project Gutenburg text (n=1,238,957, 150 iterations). Here are the results, roughly from fastest to slowest. All measurements are in ticks (10,000 ticks = 1 ms) and all relative notes are compared to the [slowest] StringBuilderimplementation. For the code used, see below or the test framework repowhere I now maintain the code for running this.

我通过一些粗略的Stopwatch性能测试运行了各种转换方法中的每一种,运行随机句子(n=61,1000 次迭代)和运行 Project Gutenburg 文本(n=1,238,957,150 次迭代)。以下是结果,大致从最快到最慢。所有测量均以滴答为单位(10,000 滴答 = 1 毫秒),并且所有相关音符都与 [最慢]StringBuilder实现进行比较。对于使用的代码,请参见下文或我现在维护运行此代码的测试框架存储库

Disclaimer

免责声明

WARNING: Do not rely on these stats for anything concrete; they are simply a sample run of sample data. If you really need top-notch performance, please test these methods in an environment representative of your production needs with data representative of what you will use.

警告:对于任何具体的事情,不要依赖这些统计数据;它们只是样本数据的样本运行。如果您确实需要一流的性能,请在代表您的生产需求的环境中测试这些方法,并使用代表您将使用的数据的数据。

Results

结果

Lookup tables have taken the lead over byte manipulation. Basically, there is some form of precomputing what any given nibble or byte will be in hex. Then, as you rip through the data, you simply look up the next portion to see what hex string it would be. That value is then added to the resulting string output in some fashion. For a long time byte manipulation, potentially harder to read by some developers, was the top-performing approach.

查找表已经领先于字节操作。基本上,有某种形式的预计算任何给定的半字节或字节将是十六进制的。然后,当您翻阅数据时,您只需查找下一部分以查看它是什么十六进制字符串。然后以某种方式将该值添加到结果字符串输出中。长期以来,一些开发人员可能难以阅读的字节操作是性能最佳的方法。

Your best bet is still going to be finding some representative data and trying it out in a production-like environment. If you have different memory constraints, you may prefer a method with fewer allocations to one that would be faster but consume more memory.

您最好的选择仍然是找到一些有代表性的数据并在类似生产的环境中进行尝试。如果您有不同的内存限制,您可能更喜欢分配较少的方法,而不是速度更快但消耗更多内存的方法。

Testing Code

测试代码

Feel free to play with the testing code I used. A version is included here but feel free to clone the repoand add your own methods. Please submit a pull request if you find anything interesting or want to help improve the testing framework it uses.

随意使用我使用的测试代码。这里包含一个版本,但可以随意克隆repo并添加您自己的方法。如果您发现任何有趣的内容或想要帮助改进它使用的测试框架,请提交拉取请求。

  1. Add the new static method (Func<byte[], string>) to /Tests/ConvertByteArrayToHexString/Test.cs.
  2. Add that method's name to the TestCandidatesreturn value in that same class.
  3. Make sure you are running the input version you want, sentence or text, by toggling the comments in GenerateTestInputin that same class.
  4. Hit F5and wait for the output (an HTML dump is also generated in the /bin folder).
  1. 将新的静态方法 ( Func<byte[], string>)添加到 /Tests/ConvertByteArrayToHexString/Test.cs。
  2. 将该方法的名称添加到TestCandidates同一个类中的返回值。
  3. 通过切换GenerateTestInput同一类中的评论,确保您正在运行您想要的输入版本,句子或文本。
  4. 点击F5并等待输出(在 /bin 文件夹中也会生成一个 HTML 转储)。
static string ByteArrayToHexStringViaStringJoinArrayConvertAll(byte[] bytes) {
    return string.Join(string.Empty, Array.ConvertAll(bytes, b => b.ToString("X2")));
}
static string ByteArrayToHexStringViaStringConcatArrayConvertAll(byte[] bytes) {
    return string.Concat(Array.ConvertAll(bytes, b => b.ToString("X2")));
}
static string ByteArrayToHexStringViaBitConverter(byte[] bytes) {
    string hex = BitConverter.ToString(bytes);
    return hex.Replace("-", "");
}
static string ByteArrayToHexStringViaStringBuilderAggregateByteToString(byte[] bytes) {
    return bytes.Aggregate(new StringBuilder(bytes.Length * 2), (sb, b) => sb.Append(b.ToString("X2"))).ToString();
}
static string ByteArrayToHexStringViaStringBuilderForEachByteToString(byte[] bytes) {
    StringBuilder hex = new StringBuilder(bytes.Length * 2);
    foreach (byte b in bytes)
        hex.Append(b.ToString("X2"));
    return hex.ToString();
}
static string ByteArrayToHexStringViaStringBuilderAggregateAppendFormat(byte[] bytes) {
    return bytes.Aggregate(new StringBuilder(bytes.Length * 2), (sb, b) => sb.AppendFormat("{0:X2}", b)).ToString();
}
static string ByteArrayToHexStringViaStringBuilderForEachAppendFormat(byte[] bytes) {
    StringBuilder hex = new StringBuilder(bytes.Length * 2);
    foreach (byte b in bytes)
        hex.AppendFormat("{0:X2}", b);
    return hex.ToString();
}
static string ByteArrayToHexViaByteManipulation(byte[] bytes) {
    char[] c = new char[bytes.Length * 2];
    byte b;
    for (int i = 0; i < bytes.Length; i++) {
        b = ((byte)(bytes[i] >> 4));
        c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
        b = ((byte)(bytes[i] & 0xF));
        c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
    }
    return new string(c);
}
static string ByteArrayToHexViaByteManipulation2(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);
}
static string ByteArrayToHexViaSoapHexBinary(byte[] bytes) {
    SoapHexBinary soapHexBinary = new SoapHexBinary(bytes);
    return soapHexBinary.ToString();
}
static string ByteArrayToHexViaLookupAndShift(byte[] bytes) {
    StringBuilder result = new StringBuilder(bytes.Length * 2);
    string hexAlphabet = "0123456789ABCDEF";
    foreach (byte b in bytes) {
        result.Append(hexAlphabet[(int)(b >> 4)]);
        result.Append(hexAlphabet[(int)(b & 0xF)]);
    }
    return result.ToString();
}
static readonly uint* _lookup32UnsafeP = (uint*)GCHandle.Alloc(_Lookup32, GCHandleType.Pinned).AddrOfPinnedObject();
static string ByteArrayToHexViaLookup32UnsafeDirect(byte[] bytes) {
    var lookupP = _lookup32UnsafeP;
    var result = new string((char)0, bytes.Length * 2);
    fixed (byte* bytesP = bytes)
    fixed (char* resultP = result) {
        uint* resultP2 = (uint*)resultP;
        for (int i = 0; i < bytes.Length; i++) {
            resultP2[i] = lookupP[bytesP[i]];
        }
    }
    return result;
}
static uint[] _Lookup32 = Enumerable.Range(0, 255).Select(i => {
    string s = i.ToString("X2");
    return ((uint)s[0]) + ((uint)s[1] << 16);
}).ToArray();
static string ByteArrayToHexViaLookupPerByte(byte[] bytes) {
    var result = new char[bytes.Length * 2];
    for (int i = 0; i < bytes.Length; i++)
    {
        var val = _Lookup32[bytes[i]];
        result[2*i] = (char)val;
        result[2*i + 1] = (char) (val >> 16);
    }
    return new string(result);
}
static string ByteArrayToHexViaLookup(byte[] bytes) {
    string[] hexStringTable = new string[] {
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
        "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
        "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
        "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
        "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
        "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
        "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
        "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
        "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
        "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
        "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
        "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
        "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
        "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
        "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
        "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF",
    };
    StringBuilder result = new StringBuilder(bytes.Length * 2);
    foreach (byte b in bytes) {
        result.Append(hexStringTable[b]);
    }
    return result.ToString();
}

Update (2010-01-13)

更新 (2010-01-13)

Added Waleed's answer to analysis. Quite fast.

添加了 Waleed 对分析的回答。蛮快。

Update (2011-10-05)

更新 (2011-10-05)

Added string.ConcatArray.ConvertAllvariant for completeness (requires .NET 4.0). On par with string.Joinversion.

string.ConcatArray.ConvertAll为完整性添加了变体(需要 .NET 4.0)。与string.Join版本相当。

Update (2012-02-05)

更新 (2012-02-05)

Test repo includes more variants such as StringBuilder.Append(b.ToString("X2")). None upset the results any. foreachis faster than {IEnumerable}.Aggregate, for instance, but BitConverterstill wins.

测试存储库包括更多变体,例如StringBuilder.Append(b.ToString("X2")). 没有人对结果感到不安。例如,foreach比 快{IEnumerable}.Aggregate,但BitConverter仍然获胜。

Update (2012-04-03)

更新 (2012-04-03)

Added Mykroft's SoapHexBinaryanswer to analysis, which took over third place.

将 Mykroft 的SoapHexBinary答案添加到分析中,排名第三。

Update (2013-01-15)

更新 (2013-01-15)

Added CodesInChaos's byte manipulation answer, which took over first place (by a large margin on large blocks of text).

添加了 CodesInChaos 的字节操作答案,它占据了第一位(在大文本块上有很大的差距)。

Update (2013-05-23)

更新 (2013-05-23)

Added Nathan Moinvaziri's lookup answer and the variant from Brian Lambert's blog. Both rather fast, but not taking the lead on the test machine I used (AMD Phenom 9750).

添加了 Nathan Moinvaziri 的查找答案以及来自 Brian Lambert 博客的变体。两者都相当快,但在我使用的测试机器(AMD Phenom 9750)上并没有领先。

Update (2014-07-31)

更新 (2014-07-31)

Added @CodesInChaos's new byte-based lookup answer. It appears to have taken the lead on both the sentence tests and the full-text tests.

添加了@CodesInChaos 的新的基于字节的查找答案。它似乎在句子测试和全文测试中都处于领先地位。

Update (2015-08-20)

更新 (2015-08-20)

Added airbreather'soptimizations and unsafevariant to this answer's repo. If you want to play in the unsafe game, you can get some huge performance gains over any of the prior top winners on both short strings and large texts.

在此答案的 repo 中添加了空气呼吸器的优化和unsafe变体。如果你想在不安全的游戏中玩,你可以在短字符串和大文本上获得比之前任何一个顶级赢家更大的性能提升。

回答by Waleed Eissa

I just encountered the very same problem today, and I came across this code:

我今天刚遇到同样的问题,我遇到了这段代码:

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

Source: Forum post byte[] Array to Hex String(see the post by PZahra). I modified the code a little to remove the 0x prefix.

来源:论坛帖子byte[] Array to Hex String(见 PZahra 的帖子)。我稍微修改了代码以删除 0x 前缀。

I did some performance testing to the code and it was almost eight times faster than using BitConverter.ToString() (the fastest according to patridge's post).

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

回答by Hyman Straw

And for inserting into an SQL string (if you're not using command parameters):

并插入到 SQL 字符串中(如果您不使用命令参数):

public static String ByteArrayToSQLHexString(byte[] Source)
{
    return = "0x" + BitConverter.ToString(Source).Replace("-", "");
}

回答by Olipro

If you want to get the "4x speed increase" reported by wcoenen, then if it's not obvious: replace hex.Substring(i, 2)with hex[i]+hex[i+1]

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

You could also take it a step further and get rid of the i+=2by using i++in both places.

您也可以更进一步,i+=2通过i++在两个地方使用来摆脱。

回答by Chris F

This is a great post. I like Waleed's solution. I haven't run it through patridge's test but it seems to be quite fast. I also needed the reverse process, converting a hex string to a byte array, so I wrote it as a reversal of Waleed's solution. Not sure if it's any faster than Tomalak's original solution. Again, I did not run the reverse process through patridge's test either.

这是一个很棒的帖子。我喜欢 Waleed 的解决方案。我还没有通过 patridge 的测试运行它,但它似乎相当快。我还需要反向过程,将十六进制字符串转换为字节数组,因此我将其编写为 Waleed 解决方案的反向过程。不确定它是否比 Tomalak 的原始解决方案更快。同样,我也没有通过 patridge 的测试运行相反的过程。

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

回答by Mykroft

There's a class called SoapHexBinarythat does exactly what you want.

有一个名为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();
}