206 votes

Code Java pour convertir un octet en hexadécimal

J'ai un tableau d'octets. Je veux que chaque chaîne d'octets de ce tableau soit convertie en sa valeur hexadécimale correspondante.

Existe-t-il une fonction en Java pour convertir un tableau d'octets en hexadécimal ?

2 votes

Ce que vous appelez tableau d'octets en Java est appelé chaîne d'octets dans d'autres langages (par ex. docs.racket-lang.org/guide/bytestrings.html )

348voto

polygenelubricants Points 136838
    byte[] bytes = {-1, 0, 1, 2, 3 };
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02X ", b));
    }
    System.out.println(sb.toString());
    // prints "FF 00 01 02 03 "

Voir aussi

  • java.util.Formatter syntaxe
    • %[flags][width]conversion
      • Drapeau '0' - Le résultat sera mis à zéro
      • Largeur 2
      • Conversion 'X' - Le résultat est formaté sous la forme d'un nombre entier hexadécimal, en majuscules.

En regardant le texte de la question, il est également possible que ce soit ce qui est demandé :

    String[] arr = {"-1", "0", "10", "20" };
    for (int i = 0; i < arr.length; i++) {
        arr[i] = String.format("%02x", Byte.parseByte(arr[i]));
    }
    System.out.println(java.util.Arrays.toString(arr));
    // prints "[ff, 00, 0a, 14]"

Plusieurs réponses ici utilise Integer.toHexString(int) C'est faisable, mais avec quelques réserves. Puisque le paramètre est un int une conversion primitive d'élargissement est effectuée sur la base de l'adresse de l'utilisateur. byte argument, qui implique l'extension du signe.

    byte b = -1;
    System.out.println(Integer.toHexString(b));
    // prints "ffffffff"

Le système 8-bit byte qui est signé en Java, est prolongé par un signe en 32 bits. int . Pour défaire efficacement cette extension de signe, on peut masquer le byte con 0xFF .

    byte b = -1;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "ff"

Un autre problème lié à l'utilisation de toHexString c'est qu'il ne contient pas de zéros :

    byte b = 10;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "a"

Ces deux facteurs combinés devraient permettre à l String.format solution plus préférable.

Références

0 votes

@Vivek : qu'est-ce qu'une "valeur extrêmement grande" ? Quelle est l'entrée et quelle est la sortie ?

0 votes

Laissez-moi vous expliquer à nouveau... J'ai une collection de chaînes d'octets dans un tableau. Mais ce que je dois faire est d'analyser chaque octet séparément... Donc, je ne veux pas travailler sur l'ensemble du tableau, mais sur chaque chaîne d'octets à la fois, qui est un composant de ce tableau... La confusion est due au mot "tableau". Maintenant dans le code ci-dessous " byte bv = 10 ; String hexString = Integer.toHexString(bv) ; " CAse 1 (Byte Recieved : 68 Hex Output : : 44) Case : 2 (Byte Recieved : -46 Hex Output : : ffffffd2)......... Pourquoi est-ce que j'obtiens un résultat aussi inattendu pour certaines valeurs ?

1 votes

@Vivek : lisez ma réponse au sujet de l'utilisation des toHexString . Vous devez le masquer avec & 0xFF c'est-à-dire Integer.toHexString(-46 & 0xFF) es "d2" .

80voto

jsinglet Points 41

Je poste cette question parce qu'aucune des réponses existantes n'explique pourquoi leurs approches fonctionnent, ce qui, à mon avis, est vraiment important pour ce problème. Dans certains cas, cela fait que la solution proposée semble inutilement compliquée et subtile. Pour illustrer mon propos, je vais proposer une approche assez simple, mais je vais fournir un peu plus de détails pour aider à l'illustrer pourquoi ça marche.

Tout d'abord, qu'est-ce qu'on essaie de faire ? Nous voulons convertir une valeur d'octet (ou un tableau d'octets) en une chaîne qui représente une valeur hexadécimale en ASCII. La première étape consiste donc à déterminer ce qu'est exactement un octet en Java :

Le type de données octet est un Nombre entier de complément à deux signé de 8 bits . Il a une valeur minimale de -128 et une valeur maximale de 127 (inclus). Le type de données byte peut être utile pour économiser de la mémoire dans les grands tableaux, où l'économie de mémoire est réellement importante. Ils peuvent également être utilisés à la place de int lorsque leurs limites aident à clarifier votre code ; le fait que la plage d'une variable soit limitée peut servir de documentation.

Qu'est-ce que cela signifie ? Plusieurs choses : Tout d'abord, et c'est le plus important, cela signifie que nous travaillons avec 8 bits . Ainsi, par exemple, nous pouvons écrire le nombre 2 sous la forme 0000 0010. Cependant, comme il s'agit d'un complément à deux, nous écrivons un 2 négatif comme ceci : 1111 1110. Ce que cela signifie également, c'est que la conversion en hexadécimal est très simple. Il suffit de convertir chaque segment de 4 bits directement en hexadécimal. Notez que pour comprendre les nombres négatifs dans ce schéma, vous devez d'abord comprendre le complément à deux. Si vous ne comprenez pas encore le complément à deux, vous pouvez lire une excellente explication ici : http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


Conversion du complément à deux en hexadécimal En général

Une fois qu'un nombre est en complément à deux, il est très simple de le convertir en hexadécimal. En général, la conversion du binaire en hexadécimal est très simple, et comme vous le verrez dans les deux exemples suivants, vous pouvez passer directement du complément à deux à l'hexadécimal.

Exemples

Exemple 1 : Convertir 2 en Hex.

1) Convertissez d'abord 2 en binaire en complément à deux :

2 (base 10) = 0000 0010 (base 2)

2) Maintenant, convertissez le binaire en hexadécimal :

0000 = 0x0 in hex
0010 = 0x2 in hex

therefore 2 = 0000 0010 = 0x02. 

Exemple 2 : Convertir -2 (en complément à deux) en Hex.

1) Convertissez d'abord -2 en binaire en complément à deux :

-2 (base 10) = 0000 0010 (direct conversion to binary) 
               1111 1101 (invert bits)
               1111 1110 (add 1)
therefore: -2 = 1111 1110 (in two's complement)

2) Maintenant, convertissez en Hex :

1111 = 0xF in hex
1110 = 0xE in hex

therefore: -2 = 1111 1110 = 0xFE.

Faire cela en Java

Maintenant que nous avons abordé le concept, vous verrez que nous pouvons obtenir ce que nous voulons avec quelques masques et décalages simples. Ce qu'il faut comprendre, c'est que l'octet que vous essayez de convertir est déjà en complément à deux. Vous ne faites pas cette conversion vous-même. Je pense que c'est un point de confusion majeur sur cette question. Prenons par exemple le tableau d'octets suivant :

byte[] bytes = new byte[]{-2,2};

Nous venons de les convertir manuellement en hexagone, ci-dessus, mais comment le faire en Java ? Voici comment :

Étape 1 : Créer un StringBuffer pour contenir notre calcul.

StringBuffer buffer = new StringBuffer();

Étape 2 : Isolez les bits d'ordre supérieur, convertissez-les en hexadécimal, et ajoutez-les au tampon.

Étant donné le nombre binaire 1111 1110, nous pouvons isoler les bits d'ordre supérieur en les décalant d'abord de 4, puis en mettant à zéro le reste du nombre. Logiquement, c'est simple, mais les détails de mise en œuvre en Java (et dans de nombreux langages) introduisent un problème à cause de l'extension du signe. Essentiellement, lorsque vous décalez une valeur d'octet, Java convertit d'abord votre valeur en un nombre entier, puis effectue une extension de signe. Ainsi, alors que vous vous attendez à ce que 1111 1110 >> 4 soit 0000 1111, en réalité, en Java, cette valeur est représentée par le complément à deux 0xFFFFFFFF !

Revenons donc à notre exemple :

1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)

On peut alors isoler les bits avec un masque :

1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex. 

En Java, nous pouvons faire tout cela en une seule fois :

Character.forDigit((bytes[0] >> 4) & 0xF, 16);

La fonction forDigit fait simplement correspondre le nombre que vous lui transmettez à l'ensemble des nombres hexadécimaux 0 à F.

Étape 3 : Ensuite, nous devons isoler les bits d'ordre inférieur. Puisque les bits que nous voulons sont déjà dans la bonne position, nous pouvons simplement les masquer :

1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.  

Comme auparavant, en Java, nous pouvons faire tout cela en une seule fois :

Character.forDigit((bytes[0] & 0xF), 16);

En mettant tout cela ensemble, nous pouvons le faire comme une boucle for et convertir le tableau entier :

for(int i=0; i < bytes.length; i++){
    buffer.append(Character.forDigit((bytes[i] >> 4) & 0xF, 16));
    buffer.append(Character.forDigit((bytes[i] & 0xF), 16));
}

Nous espérons que cette explication rendra les choses plus claires pour ceux d'entre vous qui se demandent ce qui se passe exactement dans les nombreux exemples que vous trouverez sur Internet. J'espère ne pas avoir fait d'erreurs flagrantes, mais les suggestions et corrections sont les bienvenues !

5 votes

Meilleure réponse ! L'implémentation symétrique de la conversion d'une chaîne hexagonale en octet utiliserait alors les éléments suivants Character.digit() comme (byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))

16voto

0x2D9A3 Points 1121

Essayez de cette façon :

byte bv = 10;
String hexString = Integer.toHexString(bv);

Traitement des tableaux (si j'ai bien compris) :

byte[] bytes = {9, 10, 11, 15, 16};
StringBuffer result = new StringBuffer();
for (byte b : bytes) {
    result.append(String.format("%02X ", b));
    result.append(" "); // delimiter
}
return result.toString();

Comme l'a mentionné polygenelubricants, String.format() est la bonne réponse par rapport à Integer.toHexString() (car il traite les nombres négatifs de manière correcte).

2 votes

Ce signe s'étendra, par exemple, essayer de -1 .

0 votes

Byte bv = 10 ; String hexString = Integer.toHexString(bv) ; Cela semble fonctionner Je peux l'appliquer individuellement sur chaque élément du tableau L'autre code (Dealing with array ) donne une valeur trop grande. Quelle pourrait en être la raison ?

0 votes

@Vivek, c'est parce qu'en cas de bv il renvoie un un seul caractère hexadécimal . Alors que le reste du code renvoie un chaîne de caractères hexadécimaux . J'ai changé le code avec le délimiteur pour que vous puissiez le comprendre maintenant.

11voto

Kilian Foth Points 8619

Si vous voulez une représentation hexagonale de largeur constante, c'est-à-dire 0A au lieu de A afin de pouvoir récupérer les octets sans ambiguïté. format() :

StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
    result.append(String.format("%02X", bb));
}
return result.toString();

8voto

ajrskelton Points 43

Si vous souhaitez utiliser une bibliothèque externe, la fonction org.apache.commons.codec.binary.Hex La classe a un encodeHex qui prend un byte[] et renvoie un char[] . Cette méthode est BEAUCOUP plus rapide que l'option format, et encapsule les détails de la conversion. Elle est également accompagnée d'un decodeHex pour la conversion inverse.

4 votes

Une méthode encore plus simple consiste à utiliser les fonctions intégrées javax.xml.bind.DatatypeConverter/parseHexBinary et printHexBinary. Voir stackoverflow.com/questions/9655181/

2 votes

+1 à cette option. L'Hex possède également une méthode encodeHexString, qui prend un byte[] et renvoie un String.

0 votes

N'oubliez pas que le javax n'est pas toujours disponible.

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