Conversion 'X'- Le résultat est formaté sous la forme d'un entier hexadécimal, majuscule
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 mises en garde. Puisque le paramètre est un int, une conversion primitive d'élargissement est effectuée en byteargument, ce qui implique une extension de signe.
byte b = -1;
System.out.println(Integer.toHexString(b));
// prints "ffffffff"
Le 8 bits byte, qui est signé en Java, est étendu à un signe 32 bits int. Pour annuler efficacement cette extension de signe, on peut masquer le byteavec 0xFF.
byte b = -1;
System.out.println(Integer.toHexString(b & 0xFF));
// prints "ff"
Un autre problème avec l'utilisation toHexStringest qu'il ne remplit pas de zéros:
byte b = 10;
System.out.println(Integer.toHexString(b & 0xFF));
// prints "a"
Les deux facteurs combinés devraient rendre la String.formatsolution plus préférable.
@Vivek: qu'est-ce qu'une "valeur extrêmement élevée"? Quelle est l'entrée et quelle est la sortie?
polygenelubricants
Permettez-moi de 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 le tableau entier, mais une chaîne d'octets individuelle à la fois, c'est un composant de ce tableau. La confusion est survenue à cause du 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?
Vivek
1
@Vivek: lisez ma réponse sur l'utilisation toHexString. Vous devez le masquer avec & 0xFF, c'est Integer.toHexString(-46 & 0xFF)-à- dire "d2".
polygenelubricants
@polygenelubricants: Merci beaucoup .. Il semble que finalement le code fonctionne bien .. Est-il sûr d'utiliser la fonction toHexString maintenant? Ou, il pourrait y avoir des failles avec l'approche?
Vivek
1
@Vivek: c'est "sûr", il faut juste faire attention et s'assurer de masquer la bytevaleur avec à & 0xFFchaque fois. la formatsolution ci-dessus peut également nécessiter un masquage en fonction de ce que vous utilisez réellement comme argument.
polygenelubricants
68
Je poste 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 apparaître la solution proposée inutilement compliquée et subtile. Pour illustrer, je vais fournir une approche assez simple, mais je vais fournir un peu plus de détails pour aider à illustrer pourquoi cela fonctionne.
Tout d'abord, qu'essayons-nous 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écouvrir exactement ce qu'est un octet en Java:
Le type de données octet est un 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 octet peut être utile pour économiser de la mémoire dans de grands tableaux, où les économies de mémoire sont réellement importantes. Ils peuvent également être utilisés à la place de int où leurs limites aident à clarifier votre code; le fait que la plage d'une variable soit limitée peut servir de forme de documentation.
Qu'est-ce que ça veut dire? Quelques petites choses: d'abord et surtout, cela signifie que nous travaillons avec 8 bits . Ainsi, par exemple, nous pouvons écrire le nombre 2 comme 0000 0010. Cependant, comme il s'agit du complément à deux, nous écrivons un 2 négatif comme ceci: 1111 1110. Cela signifie également que la conversion en hexadécimal est très simple. Autrement dit, vous convertissez simplement chaque segment de 4 bits directement en hexadécimal. Notez que pour donner un sens aux nombres négatifs dans ce schéma, vous devez d'abord comprendre le complément à deux. Si vous ne comprenez pas déjà 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 hexagone 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 de 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'hex.
Exemples
Exemple 1: Convertissez 2 en hexadécimal.
1) Commencez par convertir 2 en binaire en complément à deux:
2 (base 10) = 00000010 (base 2)
2) Maintenant, convertissez le binaire en hexadécimal:
0000 = 0x0 in hex
0010 = 0x2 in hex
therefore 2 = 00000010 = 0x02.
Exemple 2: Convertissez -2 (en complément à deux) en Hex.
1) Commencez par convertir -2 en binaire en complément à deux:
1111 = 0xF in hex
1110 = 0xE in hex
therefore: -2 = 11111110 = 0xFE.
Faire cela en Java
Maintenant que nous avons couvert le concept, vous constaterez que nous pouvons réaliser ce que nous voulons avec un simple masquage et décalage. La chose clé à comprendre 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. Prenez par exemple le tableau d'octets suivant:
byte[] bytes = newbyte[]{-2,2};
Nous les avons simplement convertis manuellement en hexadécimal, ci-dessus, mais comment pouvons-nous le faire en Java? Voici comment:
Étape 1: Créez 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, cependant, les détails d'implémentation en Java (et dans de nombreux langages) introduisent une ride à cause de l'extension de signe. Essentiellement, lorsque vous déplacez une valeur d'octet, Java convertit d'abord votre valeur en un entier, puis effectue l'extension de signe. Ainsi, alors que vous vous attendez à ce que 1111 1110 >> 4 soit 0000 1111, en réalité, en Java, il est représenté comme le complément à deux 0xFFFFFFFF!
Revenons donc à notre exemple:
11111110 >> 4 (shift right 4) = 11111111111111111111111111111111 (32 bit sign-extended number in two's complement)
En Java, nous pouvons faire tout cela d'un seul coup:
Character.forDigit((bytes[0] >> 4) & 0xF, 16);
La fonction forDigit mappe simplement le nombre que vous lui passez sur 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:
11111110 & 0xF = 00000000000000000000000000001110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.
Comme auparavant, en Java, nous pouvons faire tout cela en un seul coup:
Character.forDigit((bytes[0] & 0xF), 16);
En mettant tout cela ensemble, nous pouvons le faire comme une boucle for et convertir le tableau entier:
Espérons que cette explication rend les choses plus claires pour ceux d'entre vous qui se demandent exactement ce qui se passe dans les nombreux exemples que vous trouverez sur Internet. J'espère que je n'ai pas fait d'erreurs flagrantes, mais les suggestions et corrections sont les bienvenues!
meilleure réponse! L'implémentation symétrique d'une chaîne hexadécimale en octet serait convertie puis utiliserait Character.digit(), comme(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn
22
Le moyen le plus rapide que j'ai trouvé pour le faire est le suivant:
privatestaticfinal String HEXES = "0123456789ABCDEF";
static String getHex(byte[] raw){
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (finalbyte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
C'est environ 50 fois plus rapide que String.format. si vous souhaitez le tester:
publicclassMyTest{
privatestaticfinal String HEXES = "0123456789ABCDEF";
@Testpublicvoidtest_get_hex(){
byte[] raw = {
(byte) 0xd0, (byte) 0x0b, (byte) 0x01, (byte) 0x2a, (byte) 0x63,
(byte) 0x78, (byte) 0x01, (byte) 0x2e, (byte) 0xe3, (byte) 0x6c,
(byte) 0xd2, (byte) 0xb0, (byte) 0x78, (byte) 0x51, (byte) 0x73,
(byte) 0x34, (byte) 0xaf, (byte) 0xbb, (byte) 0xa0, (byte) 0x9f,
(byte) 0xc3, (byte) 0xa9, (byte) 0x00, (byte) 0x1e, (byte) 0xd5,
(byte) 0x4b, (byte) 0x89, (byte) 0xa3, (byte) 0x45, (byte) 0x35,
(byte) 0xd6, (byte) 0x10,
};
int N = 77777;
long t;
{
t = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (finalbyte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
}
hex.toString();
}
System.out.println(System.currentTimeMillis() - t); // 50
}
{
t = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
StringBuilder hex = new StringBuilder(2 * raw.length);
for (byte b : raw) {
hex.append(String.format("%02X", b));
}
hex.toString();
}
System.out.println(System.currentTimeMillis() - t); // 2535
}
}
}
Edit : Je viens de trouver quelque chose juste un peu plus vite et qui tient sur une ligne mais n'est pas compatible avec JRE 9. Utilisez à vos risques et périls
DatatypeConverter n'est plus disponible en Java 9. La chose dangereuse est que le code qui l'utilise sera compilé sous Java 1.8 ou antérieur (Java 9 avec les paramètres source antérieurs), mais obtiendra une exception d'exécution sous Java 9.
Stephen M -on grève-
Je seconde le point de @StephenMs: l'utiliser avec jre9 plantera avec l'exception ClassNotFound
Patrick Favre
En fait, vous pouvez simplement extraire la méthode printHexBinary du code source de src.zip de jdk, ce qui semble 1 fois plus rapide que la 1ère méthode.
Fruit
1
Si vous travaillez avec un tableau de caractères pour la constante HEXES, à la place String et charAt (), vous gagnez environ 20% de vitesse en plus.
Traiter avec tableau (si je vous 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 mentionné sur les lubrifiants polygéniques, String.format()est la bonne réponse par rapport à Integer.toHexString()(car elle traite correctement les nombres négatifs).
octet bv = 10; Chaîne hexString = Integer.toHexString (bv); Cela semble fonctionner firne .. Je peux l'appliquer individuellement sur chaque élément du tableau .. L'autre code (Traiter le tableau) donne une valeur trop grande. Quelle pourrait être la raison pour cela?
Vivek
@Vivek, c'est parce que dans le cas, bvil renvoie un seul caractère hexadécimal . Alors que le reste du code renvoie une chaîne de caractères hexadécimaux . J'ai changé le code avec le délimiteur pour que vous puissiez le comprendre maintenant.
MiKo
@Bar: vous pouvez toujours utiliser Integer.toHexStringsi vous masquez l' extension de signe byteavec 0xFFpour annuler.
polygenelubricants
CAse 1 (Octet reçu: 68 Sortie hexadécimale:: 44) Cas: 2 (Octet reçu: -46 Sortie hexadécimale:: ffffffd2) J'obtiens des valeurs de sortie inattendues en cas de tableaux d'octets négatifs ... Comment gérer cela?
Vivek
13
Un moyen court et simple de convertir byte[]en chaîne hexadécimale en utilisant BigInteger:
La classe de java.math.BigIntegerclasse système intégrée ( java.math.BigInteger ) est compatible avec les données binaires et hexadécimales:
Son a un constructeur BigInteger(signum=1, byte[])pour créer un grand entier par byte[](définir son premier paramètre signum= 1pour gérer correctement les octets négatifs)
Utilisez BigInteger.toString(16)pour convertir le grand entier en chaîne hexadécimale
Pour analyser un nombre hexadécimal, utilisez new BigInteger("ffa74b", 16)- ne gère pas correctement le zéro non significatif
Si vous souhaitez avoir le zéro non significatif dans le résultat hexadécimal, vérifiez sa taille et ajoutez le zéro manquant si nécessaire:
if (hex.length() % 2 == 1)
hex = "0" + hex;
Remarques
Utilisez new BigInteger(1, bytes), au lieu de new BigInteger(bytes), parce que Java est " cassé par conception " et que le bytetype de données ne contient pas d'octets mais de petits entiers signés [-128 ... 127]. Si le premier octet est négatif, le BigIntegersuppose que vous transmettez un grand entier négatif. Passez simplement 1comme premier paramètre ( signum=1).
La conversion de hex enbyte[] est délicate: parfois un zéro non significatif entre dans la sortie produite et il doit être nettoyé comme ceci:
DatatypeConverter n'est plus disponible en Java 9. La chose dangereuse est que le code qui l'utilise sera compilé sous Java 1.8 ou antérieur (Java 9 avec les paramètres source antérieurs), mais obtiendra une exception d'exécution sous Java 9.
Stephen M -on grève-
Triste quand vous dites que ce n'est pas dans jdk9. new BigInteger(byteArray).toString(16)est la voie à suivre alors. Y a-t-il des problèmes de perf avec ça?
priagupd
Peut-être pas des problèmes de perf, mais il manquera les zéros non significatifs (car ils n'ont aucun sens pour un nombre comme BigInteger)
Friso
On dirait qu'il est toujours dans la documentation java 9 , il semble donc que ce soit correct de l'utiliser encore d'après ce que je peux dire
Brad Parks
Je pense que comme expliqué ici, il est toujours correct d'utiliser pour java9, mais sera supprimé dans les futures versions de java. vous pourrez également l'utiliser avec le «nouveau» module jaxb autonome à partir de la version 2.3.0 .
lynx
11
Si vous voulez une représentation hexadécimale de largeur constante, c'est-à-dire 0Aau lieu de A, afin de pouvoir récupérer les octets sans ambiguïté, essayez format():
StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
result.append(String.format("%02X", bb));
}
return result.toString();
Si vous êtes heureux d'utiliser une bibliothèque externe, la org.apache.commons.codec.binary.Hexclasse a une encodeHexméthode qui prend a byte[]et retourne a char[]. Cette méthode est BEAUCOUP plus rapide que l'option de format et encapsule les détails de la conversion. Vient également avec une decodeHexméthode pour la conversion opposée.
Un moyen encore plus simple consiste à utiliser les fonctions intégrées javax.xml.bind.DatatypeConverter / parseHexBinary et printHexBinary. Voir stackoverflow.com/questions/9655181/…
Alan Thompson
2
+1 pour cette option. Le Hex a également une méthode encodeHexString, qui prend un octet [] et renvoie une chaîne.
Mingjiang Shi
n'oubliez pas que l' javaxespace de noms n'est pas toujours disponible.
Le package Bouncy Castle Crypto est une implémentation Java d'algorithmes cryptographiques. Ce fichier contient le fournisseur JCE et une API légère pour les API de cryptographie Bouncy Castle pour JDK 1.5 à JDK 1.8.
Le package Apache Commons Codec contient un encodeur et des décodeurs simples pour différents formats tels que Base64 et Hexadecimal. En plus de ces encodeurs et décodeurs largement utilisés, le progiciel de codec maintient également une collection d'utilitaires de codage phonétique.
C'est le code que j'ai trouvé pour fonctionner le plus rapidement jusqu'à présent. Je l'ai exécuté sur des tableaux de 109015 octets de longueur 32, en 23ms. Je l'exécutais sur une VM, donc il fonctionnera probablement plus vite sur du métal nu.
Ne fonctionne pas: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)retourne"-fdfcfbfb"
Martin Vysny
C'est un bon résultat. Vous travaillez avec les octets "-1", "2" ... "5". Thats bytes no visualiztion ( unicode.org ) si votre intention est de travailler avec le littéral «-1», «2» ... «5», vous devez travailler avec les valeurs de chaîne.
Wender
C'est un mauvais résultat. La valeur d'octet Java de -1 est en fait 0xFF (c'est la même chose que (int) 255) puisque les octets Java sont signés, le résultat devrait donc être FF02030405. Si vous essayez la solution @Jerinaw ci-dessus, vous verrez qu'elle imprimera la sortie correcte. Voir également la solution de Svetlin Nakov ci-dessous.
Martin Vysny
2
Voici une fonction simple pour convertir l'octet en hexadécimal
privatestatic String convertToHex(byte[] data){
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
Je ne pouvais pas comprendre ce que vous entendiez exactement par byte String, mais voici quelques conversions d'octet en String et vice versa, bien sûr, il y a beaucoup plus sur les documentations officielles
Integer intValue = 149;
La valeur d'octet correspondante est:
Byte byteValue = intValue.byteValue(); // this will convert the rightmost byte of the intValue to byte, because Byte is an 8 bit object and Integer is at least 16 bit, and it will give you a signed number in this case -107
récupère la valeur entière d'une variable Byte:
Integer anInt = byteValue.intValue(); // This will convert the byteValue variable to a signed Integer
From Byte and Integer to hex String:
Voici comment je le fais:
Integer anInt = 149
Byte aByte = anInt.byteValue();
String hexFromInt = "".format("0x%x", anInt); // This will output 0x95
String hexFromByte = "".format("0x%x", aByte); // This will output 0x95
Conversion d'un tableau d'octets en une chaîne hexadécimale:
Autant que je sache, il n'y a pas de fonction simple pour convertir tous les éléments d'un tableau de certains Objecten éléments d'un autre Object, vous devez donc le faire vous-même. Vous pouvez utiliser les fonctions suivantes:
Par exemple, pour un tableau d'octets de longueur 8, utilisez:
String.format("%016X", new BigInteger(1,bytes))
Avantages:
zéros de tête
pas de signe
uniquement les fonctions intégrées
une seule ligne de code
Désavantage:
il pourrait y avoir des moyens plus efficaces de le faire
Exemple:
byte[] bytes = newbyte[8];
Random r = new Random();
System.out.println("big-endian | two's-complement");
System.out.println("-----------------|-----------------");
for (int i = 0; i < 10; i++) {
r.nextBytes(bytes);
System.out.print(String.format("%016X", new BigInteger(1,bytes)));
System.out.print(" | ");
System.out.print(String.format("%016X", new BigInteger(bytes)));
System.out.println();
}
Réponses:
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 également
java.util.Formatter
syntaxe%[flags][width]conversion
'0'
- Le résultat sera complété par zéro2
'X'
- Le résultat est formaté sous la forme d'un entier hexadécimal, majusculeEn 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 mises en garde. Puisque le paramètre est unint
, une conversion primitive d'élargissement est effectuée enbyte
argument, ce qui implique une extension de signe.byte b = -1; System.out.println(Integer.toHexString(b)); // prints "ffffffff"
Le 8 bits
byte
, qui est signé en Java, est étendu à un signe 32 bitsint
. Pour annuler efficacement cette extension de signe, on peut masquer lebyte
avec0xFF
.byte b = -1; System.out.println(Integer.toHexString(b & 0xFF)); // prints "ff"
Un autre problème avec l'utilisation
toHexString
est qu'il ne remplit pas de zéros:byte b = 10; System.out.println(Integer.toHexString(b & 0xFF)); // prints "a"
Les deux facteurs combinés devraient rendre la
String.format
solution plus préférable.Références
byte
, du-128
au127
, inclusla source
toHexString
. Vous devez le masquer avec& 0xFF
, c'estInteger.toHexString(-46 & 0xFF)
-à- dire"d2"
.byte
valeur avec à& 0xFF
chaque fois. laformat
solution ci-dessus peut également nécessiter un masquage en fonction de ce que vous utilisez réellement comme argument.Je poste 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 apparaître la solution proposée inutilement compliquée et subtile. Pour illustrer, je vais fournir une approche assez simple, mais je vais fournir un peu plus de détails pour aider à illustrer pourquoi cela fonctionne.
Tout d'abord, qu'essayons-nous 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écouvrir exactement ce qu'est un octet en Java:
Qu'est-ce que ça veut dire? Quelques petites choses: d'abord et surtout, cela signifie que nous travaillons avec 8 bits . Ainsi, par exemple, nous pouvons écrire le nombre 2 comme 0000 0010. Cependant, comme il s'agit du complément à deux, nous écrivons un 2 négatif comme ceci: 1111 1110. Cela signifie également que la conversion en hexadécimal est très simple. Autrement dit, vous convertissez simplement chaque segment de 4 bits directement en hexadécimal. Notez que pour donner un sens aux nombres négatifs dans ce schéma, vous devez d'abord comprendre le complément à deux. Si vous ne comprenez pas déjà 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 hexagone 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 de 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'hex.
Exemples
Exemple 1: Convertissez 2 en hexadécimal.
1) Commencez par convertir 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: Convertissez -2 (en complément à deux) en Hex.
1) Commencez par convertir -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) Convertissez maintenant en hexadécimal:
1111 = 0xF in hex 1110 = 0xE in hex therefore: -2 = 1111 1110 = 0xFE.
Faire cela en Java
Maintenant que nous avons couvert le concept, vous constaterez que nous pouvons réaliser ce que nous voulons avec un simple masquage et décalage. La chose clé à comprendre 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. Prenez par exemple le tableau d'octets suivant:
byte[] bytes = new byte[]{-2,2};
Nous les avons simplement convertis manuellement en hexadécimal, ci-dessus, mais comment pouvons-nous le faire en Java? Voici comment:
Étape 1: Créez 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, cependant, les détails d'implémentation en Java (et dans de nombreux langages) introduisent une ride à cause de l'extension de signe. Essentiellement, lorsque vous déplacez une valeur d'octet, Java convertit d'abord votre valeur en un entier, puis effectue l'extension de signe. Ainsi, alors que vous vous attendez à ce que 1111 1110 >> 4 soit 0000 1111, en réalité, en Java, il est représenté comme 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 d'un seul coup:
Character.forDigit((bytes[0] >> 4) & 0xF, 16);
La fonction forDigit mappe simplement le nombre que vous lui passez sur 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 un seul coup:
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)); }
Espérons que cette explication rend les choses plus claires pour ceux d'entre vous qui se demandent exactement ce qui se passe dans les nombreux exemples que vous trouverez sur Internet. J'espère que je n'ai pas fait d'erreurs flagrantes, mais les suggestions et corrections sont les bienvenues!
la source
Character.digit()
, comme(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
Le moyen le plus rapide que j'ai trouvé pour le faire est le suivant:
private static final String HEXES = "0123456789ABCDEF"; static String getHex(byte[] raw) { final StringBuilder hex = new StringBuilder(2 * raw.length); for (final byte b : raw) { hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); } return hex.toString(); }
C'est environ 50 fois plus rapide que
String.format
. si vous souhaitez le tester:public class MyTest{ private static final String HEXES = "0123456789ABCDEF"; @Test public void test_get_hex() { byte[] raw = { (byte) 0xd0, (byte) 0x0b, (byte) 0x01, (byte) 0x2a, (byte) 0x63, (byte) 0x78, (byte) 0x01, (byte) 0x2e, (byte) 0xe3, (byte) 0x6c, (byte) 0xd2, (byte) 0xb0, (byte) 0x78, (byte) 0x51, (byte) 0x73, (byte) 0x34, (byte) 0xaf, (byte) 0xbb, (byte) 0xa0, (byte) 0x9f, (byte) 0xc3, (byte) 0xa9, (byte) 0x00, (byte) 0x1e, (byte) 0xd5, (byte) 0x4b, (byte) 0x89, (byte) 0xa3, (byte) 0x45, (byte) 0x35, (byte) 0xd6, (byte) 0x10, }; int N = 77777; long t; { t = System.currentTimeMillis(); for (int i = 0; i < N; i++) { final StringBuilder hex = new StringBuilder(2 * raw.length); for (final byte b : raw) { hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); } hex.toString(); } System.out.println(System.currentTimeMillis() - t); // 50 } { t = System.currentTimeMillis(); for (int i = 0; i < N; i++) { StringBuilder hex = new StringBuilder(2 * raw.length); for (byte b : raw) { hex.append(String.format("%02X", b)); } hex.toString(); } System.out.println(System.currentTimeMillis() - t); // 2535 } } }
Edit : Je viens de trouver quelque chose juste un peu plus vite et qui tient sur une ligne mais n'est pas compatible avec JRE 9. Utilisez à vos risques et périls
import javax.xml.bind.DatatypeConverter; DatatypeConverter.printHexBinary(raw);
la source
printHexBinary
du code source de src.zip de jdk, ce qui semble 1 fois plus rapide que la 1ère méthode.Essayez de cette façon:
byte bv = 10; String hexString = Integer.toHexString(bv);
Traiter avec tableau (si je vous 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 mentionné sur les lubrifiants polygéniques,
String.format()
est la bonne réponse par rapport àInteger.toHexString()
(car elle traite correctement les nombres négatifs).la source
-1
.bv
il renvoie un seul caractère hexadécimal . Alors que le reste du code renvoie une chaîne de caractères hexadécimaux . J'ai changé le code avec le délimiteur pour que vous puissiez le comprendre maintenant.Integer.toHexString
si vous masquez l' extension de signebyte
avec0xFF
pour annuler.Un moyen court et simple de convertir
byte[]
en chaîne hexadécimale en utilisantBigInteger
:import java.math.BigInteger; byte[] bytes = new byte[] {(byte)255, 10, 20, 30}; String hex = new BigInteger(1, bytes).toString(16); System.out.println(hex); // ff0a141e
Comment ça fonctionne?
La classe de
java.math.BigInteger
classe système intégrée ( java.math.BigInteger ) est compatible avec les données binaires et hexadécimales:BigInteger(signum=1, byte[])
pour créer un grand entier parbyte[]
(définir son premier paramètresignum
=1
pour gérer correctement les octets négatifs)BigInteger.toString(16)
pour convertir le grand entier en chaîne hexadécimalenew BigInteger("ffa74b", 16)
- ne gère pas correctement le zéro non significatifSi vous souhaitez avoir le zéro non significatif dans le résultat hexadécimal, vérifiez sa taille et ajoutez le zéro manquant si nécessaire:
if (hex.length() % 2 == 1) hex = "0" + hex;
Remarques
Utilisez
new BigInteger(1, bytes)
, au lieu denew BigInteger(bytes)
, parce que Java est " cassé par conception " et que lebyte
type de données ne contient pas d'octets mais de petits entiers signés [-128 ... 127]. Si le premier octet est négatif, leBigInteger
suppose que vous transmettez un grand entier négatif. Passez simplement1
comme premier paramètre (signum=1
).La conversion de hex en
byte[]
est délicate: parfois un zéro non significatif entre dans la sortie produite et il doit être nettoyé comme ceci:byte[] bytes = new BigInteger("ffa74b", 16).toByteArray(); if (bytes[0] == 0) { byte[] newBytes = new byte[bytes.length - 1]; System.arraycopy(bytes, 1, newBytes, 0, newBytes.length); bytes = newBytes; }
La dernière note est le si le
byte[]
a plusieurs zéros non significatifs, ils seront perdus.la source
La meilleure solution est ce badass one-liner:
String hex=DatatypeConverter.printHexBinary(byte[] b);
comme mentionné ici
la source
new BigInteger(byteArray).toString(16)
est la voie à suivre alors. Y a-t-il des problèmes de perf avec ça?Si vous voulez une représentation hexadécimale de largeur constante, c'est-à-dire
0A
au lieu deA
, afin de pouvoir récupérer les octets sans ambiguïté, essayezformat()
:StringBuilder result = new StringBuilder(); for (byte bb : byteArray) { result.append(String.format("%02X", bb)); } return result.toString();
la source
Si vous êtes heureux d'utiliser une bibliothèque externe, la
org.apache.commons.codec.binary.Hex
classe a uneencodeHex
méthode qui prend abyte[]
et retourne achar[]
. Cette méthode est BEAUCOUP plus rapide que l'option de format et encapsule les détails de la conversion. Vient également avec unedecodeHex
méthode pour la conversion opposée.la source
javax
espace de noms n'est pas toujours disponible.Vous pouvez utiliser la méthode de la bibliothèque Bouncy Castle Provider :
Dépendance Maven:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.60</version> </dependency>
ou depuis Apache Commons Codec :
Dépendance Maven:
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.11</version> </dependency>
la source
C'est le code que j'ai trouvé pour fonctionner le plus rapidement jusqu'à présent. Je l'ai exécuté sur des tableaux de 109015 octets de longueur 32, en 23ms. Je l'exécutais sur une VM, donc il fonctionnera probablement plus vite sur du métal nu.
public static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; public static char[] encodeHex( final byte[] data ){ final int l = data.length; final char[] out = new char[l<<1]; for( int i=0,j=0; i<l; i++ ){ out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4]; out[j++] = HEX_DIGITS[0x0F & data[i]]; } return out; }
Alors tu peux juste faire
String s = new String( encodeHex(myByteArray) );
la source
BigInteger n = new BigInteger(byteArray); String hexa = n.toString(16));
la source
BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)
retourne"-fdfcfbfb"
(int) 255
) puisque les octets Java sont signés, le résultat devrait donc êtreFF02030405
. Si vous essayez la solution @Jerinaw ci-dessus, vous verrez qu'elle imprimera la sortie correcte. Voir également la solution de Svetlin Nakov ci-dessous.Voici une fonction simple pour convertir l'octet en hexadécimal
private static String convertToHex(byte[] data) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < data.length; i++) { int halfbyte = (data[i] >>> 4) & 0x0F; int two_halfs = 0; do { if ((0 <= halfbyte) && (halfbyte <= 9)) buf.append((char) ('0' + halfbyte)); else buf.append((char) ('a' + (halfbyte - 10))); halfbyte = data[i] & 0x0F; } while(two_halfs++ < 1); } return buf.toString(); }
la source
D'autres ont couvert le cas général. Mais si vous avez un tableau d'octets d'une forme connue, par exemple une adresse MAC, vous pouvez:
byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }; String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
la source
La création (et la destruction) d'un groupe d'
String
instances n'est pas un bon moyen si les performances sont un problème.Veuillez ignorer ces arguments détaillés (dupliqués) vérifiant les déclarations
if
. C'est pour (un autre) but éducatif.Projet maven complet: http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/
Codage...
/** * Encodes a single nibble. * * @param decoded the nibble to encode. * * @return the encoded half octet. */ protected static int encodeHalf(final int decoded) { switch (decoded) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: return decoded + 0x30; // 0x30('0') - 0x39('9') case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: return decoded + 0x57; // 0x41('a') - 0x46('f') default: throw new IllegalArgumentException("illegal half: " + decoded); } } /** * Encodes a single octet into two nibbles. * * @param decoded the octet to encode. * @param encoded the array to which each encoded nibbles are written. * @param offset the offset in the array. */ protected static void encodeSingle(final int decoded, final byte[] encoded, final int offset) { if (encoded == null) { throw new IllegalArgumentException("null encoded"); } if (encoded.length < 2) { // not required throw new IllegalArgumentException( "encoded.length(" + encoded.length + ") < 2"); } if (offset < 0) { throw new IllegalArgumentException("offset(" + offset + ") < 0"); } if (offset >= encoded.length - 1) { throw new IllegalArgumentException( "offset(" + offset + ") >= encoded.length(" + encoded.length + ") - 1"); } encoded[offset] = (byte) encodeHalf((decoded >> 4) & 0x0F); encoded[offset + 1] = (byte) encodeHalf(decoded & 0x0F); } /** * Decodes given sequence of octets into a sequence of nibbles. * * @param decoded the octets to encode * * @return the encoded nibbles. */ protected static byte[] encodeMultiple(final byte[] decoded) { if (decoded == null) { throw new IllegalArgumentException("null decoded"); } final byte[] encoded = new byte[decoded.length << 1]; int offset = 0; for (int i = 0; i < decoded.length; i++) { encodeSingle(decoded[i], encoded, offset); offset += 2; } return encoded; } /** * Encodes given sequence of octets into a sequence of nibbles. * * @param decoded the octets to encode. * * @return the encoded nibbles. */ public byte[] encode(final byte[] decoded) { return encodeMultiple(decoded); }
Décodage...
/** * Decodes a single nibble. * * @param encoded the nibble to decode. * * @return the decoded half octet. */ protected static int decodeHalf(final int encoded) { switch (encoded) { case 0x30: // '0' case 0x31: // '1' case 0x32: // '2' case 0x33: // '3' case 0x34: // '4' case 0x35: // '5' case 0x36: // '6' case 0x37: // '7' case 0x38: // '8' case 0x39: // '9' return encoded - 0x30; case 0x41: // 'A' case 0x42: // 'B' case 0x43: // 'C' case 0x44: // 'D' case 0x45: // 'E' case 0x46: // 'F' return encoded - 0x37; case 0x61: // 'a' case 0x62: // 'b' case 0x63: // 'c' case 0x64: // 'd' case 0x65: // 'e' case 0x66: // 'f' return encoded - 0x57; default: throw new IllegalArgumentException("illegal half: " + encoded); } } /** * Decodes two nibbles into a single octet. * * @param encoded the nibble array. * @param offset the offset in the array. * * @return decoded octet. */ protected static int decodeSingle(final byte[] encoded, final int offset) { if (encoded == null) { throw new IllegalArgumentException("null encoded"); } if (encoded.length < 2) { // not required throw new IllegalArgumentException( "encoded.length(" + encoded.length + ") < 2"); } if (offset < 0) { throw new IllegalArgumentException("offset(" + offset + ") < 0"); } if (offset >= encoded.length - 1) { throw new IllegalArgumentException( "offset(" + offset + ") >= encoded.length(" + encoded.length + ") - 1"); } return (decodeHalf(encoded[offset]) << 4) | decodeHalf(encoded[offset + 1]); } /** * Encodes given sequence of nibbles into a sequence of octets. * * @param encoded the nibbles to decode. * * @return the encoded octets. */ protected static byte[] decodeMultiple(final byte[] encoded) { if (encoded == null) { throw new IllegalArgumentException("null encoded"); } if ((encoded.length & 0x01) == 0x01) { throw new IllegalArgumentException( "encoded.length(" + encoded.length + ") is not even"); } final byte[] decoded = new byte[encoded.length >> 1]; int offset = 0; for (int i = 0; i < decoded.length; i++) { decoded[i] = (byte) decodeSingle(encoded, offset); offset += 2; } return decoded; } /** * Decodes given sequence of nibbles into a sequence of octets. * * @param encoded the nibbles to decode. * * @return the decoded octets. */ public byte[] decode(final byte[] encoded) { return decodeMultiple(encoded); }
la source
C'est un moyen très rapide. Aucune bibliothèque externe nécessaire.
final protected static char[] HEXARRAY = "0123456789abcdef".toCharArray(); public static String encodeHexString( byte[] bytes ) { char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; hexChars[j * 2] = HEXARRAY[v >>> 4]; hexChars[j * 2 + 1] = HEXARRAY[v & 0x0F]; } return new String(hexChars); }
la source
Je ne pouvais pas comprendre ce que vous entendiez exactement par byte String, mais voici quelques conversions d'octet en String et vice versa, bien sûr, il y a beaucoup plus sur les documentations officielles
Integer intValue = 149;
La valeur d'octet correspondante est:
Byte byteValue = intValue.byteValue(); // this will convert the rightmost byte of the intValue to byte, because Byte is an 8 bit object and Integer is at least 16 bit, and it will give you a signed number in this case -107
récupère la valeur entière d'une variable Byte:
Integer anInt = byteValue.intValue(); // This will convert the byteValue variable to a signed Integer
From Byte and Integer to hex String:
Voici comment je le fais:
Integer anInt = 149 Byte aByte = anInt.byteValue(); String hexFromInt = "".format("0x%x", anInt); // This will output 0x95 String hexFromByte = "".format("0x%x", aByte); // This will output 0x95
Conversion d'un tableau d'octets en une chaîne hexadécimale:
Autant que je sache, il n'y a pas de fonction simple pour convertir tous les éléments d'un tableau de certains
Object
en éléments d'un autreObject
, vous devez donc le faire vous-même. Vous pouvez utiliser les fonctions suivantes:De l'octet [] à la chaîne:
public static String byteArrayToHexString(byte[] byteArray){ String hexString = ""; for(int i = 0; i < byteArray.length; i++){ String thisByte = "".format("%x", byteArray[i]); hexString += thisByte; } return hexString; }
Et de la chaîne hexadécimale à l'octet []:
public static byte[] hexStringToByteArray(String hexString){ byte[] bytes = new byte[hexString.length() / 2]; for(int i = 0; i < hexString.length(); i += 2){ String sub = hexString.substring(i, i + 2); Integer intVal = Integer.parseInt(sub, 16); bytes[i / 2] = intVal.byteValue(); String hex = "".format("0x%x", bytes[i / 2]); } return bytes; }
Il est trop tard mais j'espère que cela pourra en aider d'autres;)
la source
Voici votre méthode rapide:
private static final String[] hexes = new String[]{ "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" }; public static String byteToHex(byte b) { return hexes[b&0xFF]; }
la source
Tout comme certaines autres réponses, je recommande d'utiliser
String.format()
etBigInteger
. Mais pour interpréter le tableau d'octets comme une représentation binaire big-endian au lieu d' une représentation binaire complémentaire à deux (avec signum et utilisation incomplète de la plage de valeurs hexadécimales possible), utilisez BigInteger (int signum, byte [] magnitude) , pas BigInteger (byte [] val ) .Par exemple, pour un tableau d'octets de longueur 8, utilisez:
String.format("%016X", new BigInteger(1,bytes))
Avantages:
Désavantage:
Exemple:
byte[] bytes = new byte[8]; Random r = new Random(); System.out.println("big-endian | two's-complement"); System.out.println("-----------------|-----------------"); for (int i = 0; i < 10; i++) { r.nextBytes(bytes); System.out.print(String.format("%016X", new BigInteger(1,bytes))); System.out.print(" | "); System.out.print(String.format("%016X", new BigInteger(bytes))); System.out.println(); }
Exemple de sortie:
big-endian | two's-complement -----------------|----------------- 3971B56BC7C80590 | 3971B56BC7C80590 64D3C133C86CCBDC | 64D3C133C86CCBDC B232EFD5BC40FA61 | -4DCD102A43BF059F CD350CC7DF7C9731 | -32CAF338208368CF 82CDC9ECC1BC8EED | -7D3236133E437113 F438C8C34911A7F5 | -BC7373CB6EE580B 5E99738BE6ACE798 | 5E99738BE6ACE798 A565FE5CE43AA8DD | -5A9A01A31BC55723 032EBA783D2E9A9F | 032EBA783D2E9A9F 8FDAA07263217ABA | -70255F8D9CDE8546
la source
Utilisation
Integer.toHexString((int)b);
la source