Code Java Pour convertir un octet en hexadécimal

184

J'ai un tableau d'octets. Je veux que chaque chaîne d'octets de ce tableau soit convertie en ses valeurs hexadécimales correspondantes.

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

Vivek
la source
2
Ce que vous appelez byte-array en Java est appelé chaîne d'octets dans d'autres langues (par exemple docs.racket-lang.org/guide/bytestrings.html )
Patrick Favre

Réponses:

316
    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
      • Drapeau '0'- Le résultat sera complété par zéro
      • Largeur 2
      • 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.

Références

lubrifiants polygènes
la source
@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) = 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!

jsinglet
la source
4
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:

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);
Crystark
la source
2
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.
Dyorgio
15

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).

MiKo
la source
2
Cela signera étendre, par exemple essayer -1.
polygenelubricants
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:

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.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:

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.

Svetlin Nakov
la source
1
Si l'octet principal a une valeur décimale inférieure à 16, vous obtiendrez également une chaîne avec un nombre impair de caractères hexadécimaux.
Alex Jorgenson
12

La meilleure solution est ce badass one-liner:

String hex=DatatypeConverter.printHexBinary(byte[] b);

comme mentionné ici

Lynx
la source
5
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();
Kilian Foth
la source
8

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.

Ajrskelton
la source
4
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.
Mene
7

Vous pouvez utiliser la méthode de la bibliothèque Bouncy Castle Provider :

org.bouncycastle.util.encoders.Hex.toHexString(byteArray);

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.

Dépendance Maven:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

ou depuis Apache Commons Codec :

org.apache.commons.codec.binary.Hex.encodeHexString(byteArray);

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.

Dépendance Maven:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>
Tout comme
la source
Oui, c'est la meilleure solution , mais nécessite une bibliothèque externe: Apache Commons Codec ( mvnrepository.com/artifact/commons-codec/commons-codec/1.11 ) ou BouncyCastle Provider ( mvnrepository.com/artifact/org.bouncycastle/bcprov- jdk15on / 1.60 )
Svetlin Nakov
5

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) );
Jerinaw
la source
3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));
Wender
la source
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

   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();
}
AzizSM
la source
2

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]); 
jww
la source
1

La création (et la destruction) d'un groupe d' Stringinstances 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);
}
Jin Kwon
la source
1

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);
    }
bapho
la source
1

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:

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

Mehdi
la source
1

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];
    }
boucle
la source
1
moche, mais probablement très efficace. :-)
Rich S
1

Tout comme certaines autres réponses, je recommande d'utiliser String.format()et BigInteger. 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:

  • 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 = 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
Jan Martin Keil
la source
-2

Utilisation

Integer.toHexString((int)b);
Juriy
la source
il n'y a pas de zéros non significatifs supplémentaires!
user1722245