383 Stimmen

byte[] in Hex-String

Wie konvertiere ich eine byte[] zu einer string ? Jedes Mal, wenn ich es versuche, bekomme ich

System.Byte[]

anstelle des Wertes.

Und wie erhalte ich den Wert in Hexadezimal- statt in Dezimalwerten?

707voto

Guffa Punkte 663241

Hierfür gibt es eine eingebaute Methode:

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

string hex = BitConverter.ToString(data);

Ergebnis: 01-02-04-08-10-20

Wenn Sie es ohne die Bindestriche wollen, entfernen Sie sie einfach:

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

Ergebnis: 010204081020

Wenn Sie eine kompaktere Darstellung wünschen, können Sie Base64 verwenden:

string base64 = Convert.ToBase64String(data);

Ergebnis: AQIECBAg

116voto

Thymine Punkte 8107

.Net5.0 Aktualisierung

Danke an @antoninkriz's Benchmark-Vergleich können wir sehen, dass Convert.ToHexString es mit Abstand der klare Sieger heute

Es wäre töricht, etwas anderes zu verwenden als Convert.ToHexString . Meiner Meinung nach gewinnt es eindeutig in den Bereichen: Lesbarkeit, Leistung, Sicherheit


Der Rest dieses Textes ist von vor dem 10. April 2012:

Ich dachte mir, ich vergleiche einfach mal die Geschwindigkeit der einzelnen hier aufgeführten Methoden. Der Code für die Geschwindigkeitstests basiert auf dieser Grundlage.

Das Ergebnis ist, dass BitConverter+String.Replace schneller zu sein scheint als die meisten anderen einfachen Methoden. Aber die Geschwindigkeit kann mit Algorithmen wie Nathan Moinvaziris ByteArrayToHexString oder Kurt's ToHex.

Ich fand es auch interessant, dass string.Concat und string.Join viel langsamer als StringBuilder-Implementierungen für lange Strings, aber ähnlich für kürzere Arrays sind. Wahrscheinlich aufgrund der Erweiterung des StringBuilders auf die längeren Strings, so dass die Einstellung der ursprünglichen Größe sollte diesen Unterschied zu negieren.

  • Ich habe jedes Stückchen Code aus einer Antwort hier übernommen:
  • BitConvertRep \= Antwort von Guffa, BitConverter und String.Replace (Ich empfehle für die meisten Fälle, [edit:] in denen Sie nicht mit Convert.ToHexString )
  • StringBuilder \= Antwort von Quintin Robinson, foreach char StringBuilder.Append
  • LinqConcat \= Antwort von Michael Buen, string.Concat von Linq erstelltes Array
  • LinqJoin \= Antwort von mloskot, string.Join von Linq built array
  • LinqAgg \= Antwort von Matthew Whited, IEnumerable.Aggregate mit StringBuilder
  • ToHex \= Antwort von Kurt, setzt Zeichen in ein Array und verwendet Byte-Werte, um Hexadezimalwerte zu erhalten
  • ByteArrayToHexString \= Antwort von Nathan Moinvaziri, ungefähr die gleiche Geschwindigkeit wie der obige ToHex, und wahrscheinlich leichter zu lesen (Ich würde empfehlen, für die Geschwindigkeit, [edit:] wo Sie nicht verwenden können Convert.ToHexString )
  • ToHexFromTable \= Verknüpft in der Antwort von Nathan Moinvaziri, für mich ist dies fast die gleiche Geschwindigkeit wie die obigen 2, aber erfordert ein Array von 256 Zeichenfolgen, die immer existieren

Mit: LONG_STRING_LENGTH = 1000 * 1024;

  • BitConvertRep-Berechnung Abgelaufene Zeit 27.202 ms (am schnellsten eingebaut/einfach)
  • StringBuilder Berechnung Verstrichene Zeit 75,723 ms (StringBuilder no reallocate)
  • LinqConcat-Berechnung Verstrichene Zeit 182,094 ms
  • LinqJoin-Berechnung Verstrichene Zeit 181,142 ms
  • LinqAgg-Berechnung Verstrichene Zeit 93,087 ms (StringBuilder mit Reallocating)
  • ToHex-Berechnung Verstrichene Zeit 19.167 ms (am schnellsten)

Mit: LONG_STRING_LENGTH = 100 * 1024; , Ähnliche Ergebnisse

  • BitConvertReplace-Berechnung Verstrichene Zeit 3431 ms
  • StringBuilder Berechnung Verstrichene Zeit 8289 ms
  • LinqConcat-Berechnung Verstrichene Zeit 21512 ms
  • LinqJoin-Berechnung Verstrichene Zeit 19433 ms
  • LinqAgg-Berechnung Verstrichene Zeit 9230 ms
  • ToHex-Berechnung Verstrichene Zeit 1976 ms

Mit: int MANY_STRING_COUNT = 1000; int MANY_STRING_LENGTH = 1024; (Gleiche Byteanzahl wie beim ersten Test, aber in verschiedenen Arrays)

  • BitConvertReplace-Berechnung Verstrichene Zeit 25,680 ms
  • StringBuilder Berechnung Verstrichene Zeit 78,411 ms
  • LinqConcat-Berechnung Verstrichene Zeit 101,233 ms
  • LinqJoin-Berechnung Verstrichene Zeit 99,311 ms
  • LinqAgg-Berechnung Verstrichene Zeit 84,660 ms
  • ToHex-Berechnung Verstrichene Zeit 18,221 ms

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

  • BitConvertReplace Berechnung Verstrichene Zeit 1347 ms
  • StringBuilder Berechnung Verstrichene Zeit 3234 ms
  • LinqConcat-Berechnung Verstrichene Zeit 5013 ms
  • LinqJoin-Berechnung Verstrichene Zeit 4826 ms
  • LinqAgg-Berechnung Verstrichene Zeit 3589 ms
  • ToHex-Berechnung Verstrichene Zeit 772 ms

Der von mir verwendete Testcode:

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

Auch eine andere Antwort mit einem ähnlichen Verfahren Ich habe unsere Ergebnisse noch nicht miteinander verglichen.

81voto

Michael Buen Punkte 37103

Hex, Linq-fu:

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

UPDATE mit der Zeit

Wie von @RubenBartelink angemerkt, ist der Code, der keine Umwandlung von IEnumerable<string> zu einem Array: ba.Select(b => b.ToString("X2")) vor 4.0 nicht funktioniert hat, funktioniert derselbe Code jetzt unter 4.0.

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

...vor .NET 4.0, die Ausgabe ist:

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

Ab .NET 4.0 hat string.Concat eine Überladung, die IEnumerable akzeptiert. Daher wird der obige Code unter 4.0 für beide Variablen s und t die gleiche Ausgabe haben

010204081020
010204081020

Vor 4.0, ba.Select(b => b.ToString("X2")) geht auf Überlastung (object arg0) den Weg für die IEnumerable<string> zu einer richtigen Überlastung zu kommen, d.h. (params string[] values) ist, müssen wir die IEnumerable<string> in ein String-Array. Vor 4.0 hat string.Concat 10 Überladungsfunktionen, in 4.0 sind es jetzt 12

42voto

Nathan Moinvaziri Punkte 5356

Hier ist eine andere Methode:

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

public static byte[] HexStringToByteArray(string Hex)
{
    byte[] Bytes = new byte[Hex.Length / 2];
    int[] HexValue = new int[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
       0x06, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
       0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };

    for (int x = 0, i = 0; i < Hex.Length; i += 2, x += 1)
    {
        Bytes[x] = (byte)(HexValue[Char.ToUpper(Hex[i + 0]) - '0'] << 4 |
                          HexValue[Char.ToUpper(Hex[i + 1]) - '0']);
    }

    return Bytes;
}

Alternativ können Sie die Übersetzungstabelle auch wie folgt vorbereiten, um noch schnellere Ergebnisse zu erzielen:

http://blogs.msdn.com/b/blambert/archive/2009/02/22/blambert-codesnip-fast-byte-array-to-hex-string-conversion.aspx

25voto

kgriffs Punkte 3940

Ich verwende gerne Erweiterungsmethoden für Konvertierungen wie diese, auch wenn sie nur Standardbibliotheksmethoden umhüllen. Im Fall von Hexadezimal-Konvertierungen verwende ich die folgende, von Hand angepasste (d. h., schnell ) Algorithmen:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X