byte []转换为十六进制字符串[重复]

本文对比了多种将字节数组转换为十六进制字符串的方法,包括BitConverter、StringBuilder、Linq等,通过不同长度的数据集测试了各自的性能,发现BitConverter+String.Replace和特定算法如ToHex在多数情况下表现最佳。

本文翻译自:byte[] to hex string [duplicate]

This question already has answers here : 这个问题已经在这里有了答案
Closed 4 years ago . 4年前关闭。

How do I convert a byte[] to a string ? 如何将byte[]转换为string Every time I attempt it, I get 每次尝试,我都会得到

System.Byte[] System.Byte []

instead of the value. 而不是价值。

Also, how do I get the value in Hex instead of a decimal? 另外,如何获取十六进制而不是十进制的值?


#1楼

参考:https://stackoom.com/question/2c64/byte-转换为十六进制字符串-重复


#2楼

I thought I would attempt to compare the speed of each of the methods listed here for the hell of it. 我以为我会比较这里列出的每种方法的速度。 I based the speed testing code off this. 我以此为基础建立了速度测试代码。

The result is that BitConverter+String.Replace seems to be faster than most other simple ways. 结果是BitConverter + String.Replace似乎比大多数其他简单方法都快。 But the speed can be improved with algorithms like Nathan Moinvaziri's ByteArrayToHexString or Kurt's ToHex. 但是可以使用Nathan Moinvaziri的ByteArrayToHexString或Kurt的ToHex之类的算法来提高速度。

I also found it interesting that string.Concat and string.Join are much slower than StringBuilder implementations for long strings, but similar for shorter arrays. 我也发现有趣的是,对于长字符串,string.Concat和string.Join比StringBuilder实现慢得多,但对于较短的数组则类似。 Probably due to expanding the StringBuilder on the longer strings, so setting the initial size should negate this difference. 可能是由于在较长的字符串上扩展了StringBuilder,因此设置初始大小应该可以消除这种差异。

  • Took each bit of code from an answer here: 从这里得到答案的每一段代码:
  • BitConvertRep = Answer by Guffa, BitConverter and String.Replace (I'd recommend for most cases) BitConvertRep = Guffa,BitConverter和String.Replace的答案(在大多数情况下,我建议使用)
  • StringBuilder = Answer by Quintin Robinson, foreach char StringBuilder.Append StringBuilder = Quintin Robinson的答案,foreach char StringBuilder.Append
  • LinqConcat = Answer by Michael Buen, string.Concat of Linq built array LinqConcat = Michael Buen的答案,字符串。Linq的Concat构建了数组
  • LinqJoin = Answer by mloskot, string.Join of Linq built array LinqJoin = mloskot的答案,字符串。Linq的连接建立数组
  • LinqAgg = Answer by Matthew Whited, IEnumerable.Aggregate with StringBuilder LinqAgg = IEnumerable的Matthew Whited的答案。与StringBuilder 聚合
  • ToHex = Answer by Kurt, sets chars in an array, using byte values to get hex ToHex = Kurt的答案,在数组中设置字符,使用字节值获取十六进制
  • ByteArrayToHexString = Answer by Nathan Moinvaziri, approx same speed as the ToHex above, and is probably easier to read (I'd recommend for speed) ByteArrayToHexString = Nathan Moinvaziri的回答,与上述ToHex的速度大致相同,并且可能更易于阅读(我建议您提高速度)
  • ToHexFromTable = Linked in answer by Nathan Moinvaziri, for me this is near the same speed as the above 2 but requires an array of 256 strings to always exist ToHexFromTable =内森·莫因瓦济里(Nathan Moinvaziri)的答案链接,对我来说,这几乎与上述2相同的速度,但始终需要256个字符串数组

With: LONG_STRING_LENGTH = 1000 * 1024; 使用: LONG_STRING_LENGTH = 1000 * 1024;

  • BitConvertRep calculation Time Elapsed 27,202 ms (fastest built in/simple) BitConvertRep计算经过的时间27,202 ms (内置/简单最快)
  • StringBuilder calculation Time Elapsed 75,723 ms (StringBuilder no reallocate) StringBuilder计算经过的时间75,723毫秒(StringBuilder无需重新分配)
  • LinqConcat calculation Time Elapsed 182,094 ms LinqConcat计算经过的时间182,094 ms
  • LinqJoin calculation Time Elapsed 181,142 ms LinqJoin计算经过的时间181,142 ms
  • LinqAgg calculation Time Elapsed 93,087 ms (StringBuilder with reallocating) LinqAgg计算经过的时间93,087 ms(带有重新分配的StringBuilder)
  • ToHex calculation Time Elapsed 19,167 ms (fastest) ToHex计算经过的时间19,167 ms (最快)

With: LONG_STRING_LENGTH = 100 * 1024; 其中: LONG_STRING_LENGTH = 100 * 1024; , Similar results ,类似结果

  • BitConvertReplace calculation Time Elapsed 3431 ms BitConvertReplace计算经过的时间3431 ms
  • StringBuilder calculation Time Elapsed 8289 ms StringBuilder计算经过的时间8289 ms
  • LinqConcat calculation Time Elapsed 21512 ms LinqConcat计算经过的时间21512 ms
  • LinqJoin calculation Time Elapsed 19433 ms LinqJoin计算经过的时间19433 ms
  • LinqAgg calculation Time Elapsed 9230 ms LinqAgg计算经过的时间9230 ms
  • ToHex calculation Time Elapsed 1976 ms ToHex计算经过的时间1976 ms

With: int MANY_STRING_COUNT = 1000; 使用: int MANY_STRING_COUNT = 1000; int MANY_STRING_LENGTH = 1024; (Same byte count as first test but in different arrays) (与第一次测试相同的字节数,但使用不同的数组)

  • BitConvertReplace calculation Time Elapsed 25,680 ms BitConvertReplace计算经过的时间25,680毫秒
  • StringBuilder calculation Time Elapsed 78,411 ms StringBuilder计算经过的时间78,411 ms
  • LinqConcat calculation Time Elapsed 101,233 ms LinqConcat计算经过的时间101,233 ms
  • LinqJoin calculation Time Elapsed 99,311 ms LinqJoin计算经过的时间99,311 ms
  • LinqAgg calculation Time Elapsed 84,660 ms LinqAgg计算经过的时间84,660 ms
  • ToHex calculation Time Elapsed 18,221 ms ToHex计算经过的时间18,221 ms

With: int MANY_STRING_COUNT = 2000; 使用: int MANY_STRING_COUNT = 2000; int MANY_STRING_LENGTH = 20;

  • BitConvertReplace calculation Time Elapsed 1347 ms BitConvertReplace计算经过的时间1347 ms
  • StringBuilder calculation Time Elapsed 3234 ms StringBuilder计算经过的时间3234 ms
  • LinqConcat calculation Time Elapsed 5013 ms LinqConcat计算经过的时间5013 ms
  • LinqJoin calculation Time Elapsed 4826 ms LinqJoin计算经过的时间4826 ms
  • LinqAgg calculation Time Elapsed 3589 ms LinqAgg计算经过的时间3589 ms
  • ToHex calculation Time Elapsed 772 ms ToHex计算经过的时间772毫秒

Testing code I used: 我使用的测试代码:

void Main()
{
    int LONG_STRING_LENGTH = 100 * 1024;
    int MANY_STRING_COUNT = 1024;
    int MANY_STRING_LENGTH = 100;

    var source = GetRandomBytes(LONG_STRING_LENGTH);

    List<byte[]> manyString = new List<byte[]>(MANY_STRING_COUNT);
    for (int i = 0; i < MANY_STRING_COUNT; ++i)
    {
        manyString.Add(GetRandomBytes(MANY_STRING_LENGTH));
    }

    var algorithms = new Dictionary<string,Func<byte[], string>>();
    algorithms["BitConvertReplace"] = BitConv;
    algorithms["StringBuilder"] = StringBuilderTest;
    algorithms["LinqConcat"] = LinqConcat;
    algorithms["LinqJoin"] = LinqJoin;
    algorithms["LinqAgg"] = LinqAgg;
    algorithms["ToHex"] = ToHex;
    algorithms["ByteArrayToHexString"] = ByteArrayToHexString;

    Console.WriteLine(" === Long string test");
    foreach (var pair in algorithms) {
        TimeAction(pair.Key + " calculation", 500, () =>
        {
            pair.Value(source);
        });
    }

    Console.WriteLine(" === Many string test");
    foreach (var pair in algorithms) {
        TimeAction(pair.Key + " calculation", 500, () =>
        {
            foreach (var str in manyString)
            {
                pair.Value(str);
            }
        });
    }
}

// Define other methods and classes here
static void TimeAction(string description, int iterations, Action func) {
    var watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < iterations; i++) {
        func();
    }
    watch.Stop();
    Console.Write(description);
    Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}

//static byte[] GetRandomBytes(int count) {
//  var bytes = new byte[count];
//  (new Random()).NextBytes(bytes);
//  return bytes;
//}
static Random rand = new Random();
static byte[] GetRandomBytes(int count) {
    var bytes = new byte[count];
    rand.NextBytes(bytes);
    return bytes;
}


static string BitConv(byte[] data)
{
    return BitConverter.ToString(data).Replace("-", string.Empty);
}
static string StringBuilderTest(byte[] data)
{
    StringBuilder sb = new StringBuilder(data.Length*2);
    foreach (byte b in data)
        sb.Append(b.ToString("X2"));

    return sb.ToString();
}
static string LinqConcat(byte[] data)
{
    return string.Concat(data.Select(b => b.ToString("X2")).ToArray());
}
static string LinqJoin(byte[] data)
{
    return string.Join("",
        data.Select(
            bin => bin.ToString("X2")
            ).ToArray());
}
static string LinqAgg(byte[] data)
{
    return data.Aggregate(new StringBuilder(),
                               (sb,v)=>sb.Append(v.ToString("X2"))
                              ).ToString();
}
static string ToHex(byte[] bytes)
{
    char[] c = new char[bytes.Length * 2];

    byte b;

    for(int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx)
    {
        b = ((byte)(bytes[bx] >> 4));
        c[cx] = (char)(b > 9 ? b - 10 + 'A' : b + '0');

        b = ((byte)(bytes[bx] & 0x0F));
        c[++cx] = (char)(b > 9 ? b - 10 + 'A' : b + '0');
    }

    return new string(c);
}
public static string ByteArrayToHexString(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();
}

Also another answer with a similar process , I haven't compared our results yet. 另外一个具有类似过程的答案 ,我还没有比较我们的结果。


#3楼

With: 带有:

byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x0D, 0x0E, 0x0F };
string hex = string.Empty;
data.ToList().ForEach(b => hex += b.ToString("x2"));
// use "X2" for uppercase hex letters
Console.WriteLine(hex);

Result: 0102030d0e0f 结果: 0102030d0e0f


#4楼

private static string GuidToRaw(Guid guid)
{
    byte[] bytes = guid.ToByteArray();

    int сharCount = bytes.Length * 2;
    char[] chars = new char[сharCount];

    int index = 0;
    for (int i = 0; i < сharCount; i += 2)
    {
        byte b = bytes[index++];
        chars[i] = GetHexValue((int)(b / 16));
        chars[i + 1] = GetHexValue((int)(b % 16));
    }
    return new string(chars, 0, chars.Length);
}

private static char GetHexValue(int i)
{
    return (char)(i < 10 ? i + 48 : i + 55);
}

#5楼

I think I made a faster byte array to string convertor: 我想我做了一个更快的字节数组到字符串转换器:

public static class HexTable
{
    private static readonly string[] table = BitConverter.ToString(Enumerable.Range(0, 256).Select(x => (byte)x).ToArray()).Split('-');

    public static string ToHexTable(byte[] value)
    {
        StringBuilder sb = new StringBuilder(2 * value.Length);

        for (int i = 0; i < value.Length; i++)
            sb.Append(table[value[i]]);

        return sb.ToString();
    }

And the test set up: 并进行测试设置:

static void Main(string[] args)
{
        const int TEST_COUNT = 10000;
        const int BUFFER_LENGTH = 100000;

        Random random = new Random();

        Stopwatch sw = new Stopwatch();
        Stopwatch sw2 = new Stopwatch();

        byte[] buffer = new byte[BUFFER_LENGTH];
        random.NextBytes(buffer);

        sw.Start();
        for (int j = 0; j < TEST_COUNT; j++)
            HexTable.ToHexTable(buffer);

        sw.Stop();

        sw2.Start();
        for (int j = 0; j < TEST_COUNT; j++)
            ToHexChar.ToHex(buffer);

        sw2.Stop();

        Console.WriteLine("Hex Table Elapsed Milliseconds: {0}", sw.ElapsedMilliseconds);
        Console.WriteLine("ToHex Elapsed Milliseconds: {0}", sw2.ElapsedMilliseconds);
    }

The ToHexChar.ToHEx() method is the ToHex() method shown previously. ToHexChar.ToHEx()方法是前面显示的ToHex()方法。

Results are as follows: 结果如下:

HexTable = 11808 ms ToHEx = 12168ms HexTable = 11808 ms ToHEx = 12168ms

It may not look that much of a difference, but it's still faster :) 它看起来似乎没有太大的区别,但是仍然更快:)


#6楼

Just to add one more answer to the pile, there is a System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary class that I've used which can convert bytes to and from hex: 只是为了给堆增加一个答案,这里有一个System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary类,该类可以将字节与十六进制进行转换:

string hex = new SoapHexBinary(bytes).ToString();
byte[] bytes = SoapHexBinary.Parse(hex).Value;

Not sure how it compares (benchmark) to other implementations, but IMO it is pretty simple -- especially for converting from hex back into bytes. 不确定将其与其他实现进行比较(基准),但是IMO非常简单-尤其是从十六进制转换回字节时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值