171 Stimmen

Wie konvertiere ich in Java ein Byte-Array in eine Zeichenkette aus Hex-Ziffern, wobei führende Nullen erhalten bleiben?

Ich arbeite mit einigen Beispiel-Java-Code für die Herstellung von md5 Hashes. Ein Teil wandelt die Ergebnisse von Bytes in eine Zeichenkette aus Hex-Ziffern um:

byte messageDigest[] = algorithm.digest();     
StringBuffer hexString = new StringBuffer();
for (int i=0;i<messageDigest.length;i++) {
    hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
    }

Es funktioniert jedoch nicht ganz, da toHexString offenbar führende Nullen abschneidet. Also, was ist der einfachste Weg, um von Byte-Array zu Hex-String, die die führenden Nullen behält gehen?

22voto

Ich fand Integer.toHexString ein wenig langsam. Wenn Sie viele Bytes konvertieren, sollten Sie in Erwägung ziehen, ein Array von Strings zu erstellen, das "00" "FF" enthält, und die Ganzzahl als Index zu verwenden. D.h..

hexString.append(hexArray[0xFF & messageDigest[i]]);

Das geht schneller und garantiert die richtige Länge. Benötigt nur das Array von Strings:

String[] hexArray = {
"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"};

1 Stimmen

@Marvo 0x000000FF == 0xFF, also bringt Ihre vorgeschlagene Änderung nichts. Die Maske ist einfach ein int wie jede andere Zahl. 0xFF != -1

13voto

Ich habe für die gleiche Sache gesucht ... einige gute Ideen hier, aber ich lief ein paar Mikro-Benchmarks. Ich fand den folgenden als den schnellsten (modifiziert von Ayman's oben und etwa 2x so schnell, und etwa 50% schneller als Steve's direkt über diesem):

public static String hash(String text, String algorithm)
        throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
    return new BigInteger(1, hash).toString(16);
}

Edit: Ups - ich habe übersehen, dass dies im Wesentlichen dasselbe ist wie das von kgiannakakis und daher eine führende 0 entfernt werden kann. Wenn man dies jedoch wie folgt ändert, ist es immer noch am schnellsten:

public static String hash(String text, String algorithm)
        throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
    BigInteger bi = new BigInteger(1, hash);
    String result = bi.toString(16);
    if (result.length() % 2 != 0) {
        return "0" + result;
    }
    return result;
}

4 Stimmen

Das ist immer noch nicht richtig. Wenn der Hash lautet {0, 0, 0, 0} zum Beispiel, BigInteger 's toString wird nur geben "0" . Dieser Code stellt eine weitere "0" und gibt zurück "00" aber das Ergebnis sollte sein "00000000" .

0 Stimmen

BigInteger.toString() ist bei weitem die langsamste Methode, die ich in Java gefunden habe, etwa 100x langsamer als eine performante Implementierung, siehe stackoverflow.com/a/58118078/774398 . Auch in Ihrer Antwort wird ein Hash berechnet, aber das war nicht Teil der Frage.

0 Stimmen

Es ist nicht das, was der OP gefragt, aber OK, wenn Sie für Hash-Zeichenfolge suchen und ändern Sie die letzte zu while(Länge < erwartete Länge) ... fügen Sie Nullen vor (die meisten Hashes haben erwartete Länge, in der Regel einige Potenz von zwei wie 128)

13voto

Usagi Miyamoto Punkte 5983

Ich würde so etwas für feste Längen, wie Hashes, verwenden:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

El 0 in der Maske macht die Polsterung...

0 Stimmen

Eine Ein-Zeilen-Lösung, die nur Standard-Java verwendet!

11voto

Illarion Kovalchuk Punkte 5518
static String toHex(byte[] digest) {
    StringBuilder sb = new StringBuilder();
    for (byte b : digest) {
        sb.append(String.format("%1$02X", b));
    }

    return sb.toString();
}

3 Stimmen

Die Standard-Anfangskapazität einer StringBuilder ist 16 Zeichen lang. Ein MD5-Hash besteht aus 32 Zeichen. Nach dem Anhängen der ersten 16 Zeichen würde das interne Array in ein neues Array der Länge 34 kopiert werden. Auch String.format erstellt eine neue Formatter Instanz für jedes Byte des Digests. Und standardmäßig wird jede Formatter instanziiert eine neue StringBuilder um seine Ausgabe zu puffern. Ich denke sogar, dass es einfacher ist, nur einen Formatter mit einer StringBuffer von 32 Zeichen Anfangskapazität ( new Formatter(new StringBuilder(32)) ) und verwenden seine format y toString Methoden.

0 Stimmen

Bei variablen Digestlängen würde man natürlich eine Anfangskapazität von digest.length * 2 .

6voto

kichik Punkte 30440

Guave macht es auch ziemlich einfach:

BaseEncoding.base16().encode( bytes );

Es ist eine gute Alternative, wenn Apache Commons nicht verfügbar ist. Es hat auch einige schöne Kontrollen der Ausgabe wie:

byte[] bytes = new byte[] { 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
BaseEncoding.base16().lowerCase().withSeparator( ":", 2 ).encode( bytes );
// "0a:0b:0c:0d:0e:0f"

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