349 votes

byte[] en chaîne hexagonale

Comment convertir un byte[] à un string ? Chaque fois que je tente de le faire, j'obtiens

System.Byte[]

au lieu de la valeur.

En outre, comment puis-je obtenir la valeur en hexadécimal au lieu d'une décimale ?

645voto

Guffa Points 308133

Il existe une méthode intégrée pour cela :

byte[] data = { 1, 2, 4, 8, 16, 32 };

string hex = BitConverter.ToString(data);

Résultat : 01-02-04-08-10-20

Si vous le voulez sans les tirets, il suffit de les enlever :

string hex = BitConverter.ToString(data).Replace("-", string.Empty);

Résultat : 010204081020

Si vous souhaitez une représentation plus compacte, vous pouvez utiliser Base64 :

string base64 = Convert.ToBase64String(data);

Résultat : AQIECBAg

Ajouté par OP Mon test montre que le plus rapide est http://stackoverflow.com/a/18574846/34537

91voto

Thymine Points 2198

Je me suis dit que j'allais essayer de comparer la vitesse de chacune des méthodes énumérées ici, pour le plaisir. J'ai basé le code de test de vitesse sur ça.

Le résultat est que BitConverter+String.Replace semble être plus rapide que la plupart des autres méthodes simples. Mais la vitesse peut être améliorée avec des algorithmes tels que ByteArrayToHexString de Nathan Moinvaziri ou le ToHex de Kurt.

J'ai également trouvé intéressant que string.Concat et string.Join soient beaucoup plus lents que les implémentations de StringBuilder pour les chaînes longues, mais similaires pour les tableaux plus courts. Probablement à cause de l'expansion du StringBuilder sur les chaînes plus longues, donc fixer la taille initiale devrait annuler cette différence.

  • J'ai pris chaque bout de code d'une réponse ici :
  • BitConvertRep \= Réponse de Guffa, BitConverter et String.Replace (Je recommande pour la plupart des cas)
  • StringBuilder \= Réponse de Quintin Robinson, foreach char StringBuilder.Append
  • LinqConcat \= Réponse de Michael Buen, string.Concat d'un tableau construit par Linq.
  • LinqJoin \= Réponse de mloskot, string.Join du tableau construit par Linq
  • LinqAgg \= Réponse de Matthew Whited, IEnumerable.Aggregate avec StringBuilder
  • ToHex \= Réponse de Kurt, met les caractères dans un tableau, en utilisant les valeurs des octets pour obtenir l'hexagone.
  • ByteArrayToHexString \= Réponse de Nathan Moinvaziri, à peu près à la même vitesse que le ToHex ci-dessus, et probablement plus facile à lire. (Je recommande pour la vitesse)
  • ToHexFromTable \= Lié dans la réponse de Nathan Moinvaziri, pour moi c'est presque la même vitesse que les 2 ci-dessus mais nécessite un tableau de 256 chaînes pour toujours exister

Avec : LONG_STRING_LENGTH = 1000 * 1024;

  • Calcul de BitConvertRep Temps écoulé 27 202 ms (le plus rapide intégré/simple)
  • Calcul du StringBuilder Temps écoulé 75,723 ms (StringBuilder no reallocate)
  • Calcul de LinqConcat Temps écoulé 182,094 ms
  • Calcul de LinqJoin Temps écoulé 181,142 ms
  • Calcul de LinqAgg Temps écoulé 93,087 ms (StringBuilder avec réaffectation)
  • Calcul du ToHex Temps écoulé 19 167 ms (plus rapide)

Avec : LONG_STRING_LENGTH = 100 * 1024; Résultats similaires

  • Calcul de BitConvertReplace Temps écoulé 3431 ms
  • Calcul du StringBuilder Temps écoulé 8289 ms
  • Calcul de LinqConcat Temps écoulé 21512 ms
  • Calcul de LinqJoin Temps écoulé 19433 ms
  • Calcul de LinqAgg Temps écoulé 9230 ms
  • Calcul du ToHex Temps écoulé 1976 ms

Avec : int MANY_STRING_COUNT = 1000; int MANY_STRING_LENGTH = 1024; (Même nombre d'octets que le premier test mais dans des tableaux différents)

  • Calcul de BitConvertReplace Temps écoulé 25 680 ms
  • Calcul de StringBuilder Temps écoulé 78,411 ms
  • Calcul de LinqConcat Temps écoulé 101,233 ms
  • Calcul de LinqJoin Temps écoulé 99,311 ms
  • Calcul de LinqAgg Temps écoulé 84,660 ms
  • Calcul du ToHex Temps écoulé 18,221 ms

Avec : int MANY_STRING_COUNT = 2000; int MANY_STRING_LENGTH = 20;

  • Calcul de BitConvertReplace Temps écoulé 1347 ms
  • Calcul du StringBuilder Temps écoulé 3234 ms
  • Calcul de LinqConcat Temps écoulé 5013 ms
  • Calcul de LinqJoin Temps écoulé 4826 ms
  • Calcul de LinqAgg Temps écoulé 3589 ms
  • Calcul du ToHex Temps écoulé 772 ms

Code de test que j'ai utilisé :

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

Une autre réponse avec un processus similaire Je n'ai pas encore comparé nos résultats.

75voto

Michael Buen Points 20453

Hex, Linq-fu :

string.Concat(ba.Select(b => b.ToString("X2")).ToArray())

Mise à jour avec les temps

Comme l'a noté @RubenBartelink, le code qui n'a pas une conversion de IEnumerable<string> à un tableau : ba.Select(b => b.ToString("X2")) ne fonctionnait pas avant la version 4.0, le même code fonctionne maintenant sur la version 4.0.

Ce code...

byte[] ba = { 1, 2, 4, 8, 16, 32 };

string s = string.Concat(ba.Select(b => b.ToString("X2")));
string t = string.Concat(ba.Select(b => b.ToString("X2")).ToArray());

Console.WriteLine (s);
Console.WriteLine (t);

...avant .NET 4.0, le résultat est :

System.Linq.Enumerable+<CreateSelectIterator>c__Iterator10`2[System.Byte,System.String]
010204081020

À partir de .NET 4.0, string.Concat a une surcharge qui accepte IEnumerable. Par conséquent, en 4.0, le code ci-dessus aura le même résultat pour les deux variables s et t.

010204081020
010204081020

Avant la version 4.0, ba.Select(b => b.ToString("X2")) va en surcharge (object arg0) , la voie pour le IEnumerable<string> pour passer à une surcharge appropriée, c'est-à-dire (params string[] values) c'est que nous devons convertir le IEnumerable<string> à un tableau de chaînes de caractères. Avant la version 4.0, string.Concat comptait 10 fonctions de surcharge, alors qu'en 4.0, il en compte 12.

22voto

kgriffs Points 1839

J'aime utiliser les méthodes d'extension pour les conversions de ce type, même si elles ne font qu'envelopper les méthodes de la bibliothèque standard. Dans le cas des conversions hexadécimales, j'utilise la méthode suivante, adaptée à la main (c'est-à-dire, rapide ) des algorithmes :

public static string ToHex(this 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 + 0x37 + 0x20 : b + 0x30);

        b = ((byte)(bytes[bx] & 0x0F));
        c[++cx]=(char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30);
    }

    return new string(c);
}

public static byte[] HexToBytes(this string str)
{
    if (str.Length == 0 || str.Length % 2 != 0)
        return new byte[0];

    byte[] buffer = new byte[str.Length / 2];
    char c;
    for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
    {
        // Convert first half of byte
        c = str[sx];
        buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4);

        // Convert second half of byte
        c = str[++sx];
        buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0'));
    }

    return buffer;
}

20voto

Quintin Robinson Points 41988

Je ne convertis pas souvent des octets en hexadécimal, alors je dois dire que je ne sais pas s'il y a une meilleure façon de faire, mais voici une façon de le faire.

StringBuilder sb = new StringBuilder();
foreach (byte b in myByteArray)
    sb.Append(b.ToString("X2"));

string hexString = sb.ToString();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X