166 votes

En Java, comment convertir un tableau d'octets en une chaîne de chiffres hexadécimaux tout en conservant les zéros de tête ?

Je travaille avec un exemple de code java pour faire des hashs md5. Une partie convertit les résultats des octets en une chaîne de chiffres hexadécimaux :

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

Cependant, cela ne fonctionne pas tout à fait, car toHexString ne tient apparemment pas compte des zéros de tête. Quel est donc le moyen le plus simple de passer d'un tableau d'octets à une chaîne hexagonale en conservant les zéros de tête ?

135voto

Brandon DuRette Points 3034

Consultez le codec Apache Commons Hex.encodeHex . Le type de retour est char[] qui peut trivialement être converti en String . Donc :

  String hexString = new String(Hex.encodeHex(messageDigest));

11 votes

Et tant que vous faites md5 en utilisant Apache Commons Codec, jetez un coup d'œil à DigestUtils.md5Hex()

1 votes

DigestUtils rend les choses un peu plus faciles, mais il peut être difficile de l'inclure dans votre projet. Personnellement, je grogne à l'idée de m'embrouiller avec les fichiers pom.

113voto

Ayman Points 3980

Vous pouvez utiliser celui ci-dessous. Je l'ai testé avec des octets zéro en tête et avec des octets négatifs initiaux également.

public static String toHex(byte[] bytes) {
    BigInteger bi = new BigInteger(1, bytes);
    return String.format("%0" + (bytes.length << 1) + "X", bi);
}

Si vous voulez des chiffres hexadécimaux en minuscules, utilisez "x" dans le format String.

3 votes

Pas de dépendances externes, agréable et court. De plus, si vous savez que vous avez 16 octets / 32 chiffres hexadécimaux, votre solution se résume à une simple ligne. Cool !

0 votes

Ça marche bien, merci.

0 votes

Merci. J'en avais besoin pour convertir en Scala un tableau d'octets IPv6 de 16 octets en une chaîne hexadécimale avec un espacement de zéro : f"${BigInt(1, myIpv6ByteArray)}%032x" .

110voto

Michael Myers Points 82361

Une approche simple consisterait à vérifier combien de chiffres sont produits par Integer.toHexString(). Quelque chose comme ça :

String hex = Integer.toHexString(0xFF & messageDigest[i]);
if (hex.length() == 1) {
    // could use a for loop, but we're only dealing with a single byte
    hexString.append('0');
}
hexString.append(hex);

0 votes

Cela ne produirait-il pas "10" pour l'octet 0x01 ?

4 votes

Non, le 0 est ajouté à hexString avant la valeur hexagonale.

0 votes

Quand j'ai appelé Integer.toHexString((byte)0xff) il retourne "ffffffff" à cause de l'extension du signe. On peut donc avoir besoin de prendre les deux derniers caractères de la chaîne retournée.

40voto

Gareth Points 121

Utilisez DatatypeConverter.printHexBinary() . Vous pouvez lire sa documentation dans http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/DatatypeConverter.html

Par exemple :

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
System.out.println(javax.xml.bind.DatatypeConverter.printHexBinary(bytes));

Se traduira par :

000086003D

0 votes

Pour la marche arrière, il y a DatatypeConverter.parseHexBinary(hexString) également.

2 votes

Gardez à l'esprit qu'à partir de Java 11, java.xml ne fait plus partie du JDK.

34voto

Jemenake Points 348

J'ai aimé les propositions de Steve, mais il aurait pu se passer de quelques variables et économiser plusieurs lignes dans le processus.

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}

Ce que j'aime dans cette méthode, c'est qu'il est facile de voir exactement ce qu'elle fait (au lieu de s'appuyer sur une boîte noire magique de conversion BigInteger) et que vous n'avez pas à vous soucier des cas particuliers comme les zéros en tête et autres. Cette routine prend chaque bit de 4 bits et le transforme en un caractère hexadécimal. Et elle utilise une table de consultation, donc elle est probablement rapide. Elle pourrait probablement être plus rapide si vous remplacez v/16 et v%16 par des décalages et des ET par bit, mais je suis trop paresseux pour le tester maintenant.

0 votes

Joli ! Améliore la pensée "append is slow" de Steve en la faisant fonctionner pour tout tableau d'octets de taille arbitraire.

0 votes

Changez v/16 en v >>> 4 et v%16 en v & 0x0F pour améliorer la vitesse. Vous pouvez également utiliser j << 1 pour multiplier par 2 (bien que le compilateur le fasse probablement pour vous).

0 votes

Ou, encore mieux, ajouter la valeur à '0' pour obtenir le caractère, de sorte qu'aucune table de recherche ne soit nécessaire. par exemple, hexChars[j << 1] = (byte)(v >>> 4 + '0')

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