Convertir une représentation sous forme de chaîne d'un vidage hexadécimal en un tableau d'octets en utilisant Java?

373

Je cherche un moyen de convertir une longue chaîne (à partir d'un vidage), qui représente des valeurs hexadécimales dans un tableau d'octets.

Je n'aurais pas pu mieux le formuler que la personne qui a posé la même question ici .

Mais pour le garder original, je vais le formuler à ma façon: supposons que j'ai une chaîne "00A0BF"que je voudrais interpréter comme

byte[] {0x00,0xA0,0xBf}

que devrais-je faire?

Je suis un novice Java et j'ai fini par utiliser BigIntegeret faire attention aux zéros de tête. Mais je pense que c'est moche et je suis sûr que je manque quelque chose de simple.

rafraf
la source
J'ai apprivoisé BigInteger ici .
John McClane
FWIW String.getBytes()ne fonctionnera pas comme vous le pensez. J'ai dû l'apprendre à la dure. if ("FF".getBytes() != "ff".getBytes()) { System.out.println("Try again"); }
tir38

Réponses:

637

Voici une solution qui, je pense, est meilleure que n'importe quelle autre publiée jusqu'à présent:

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

Raisons pour lesquelles il s'agit d'une amélioration:

  • Sûr avec des zéros non significatifs (contrairement à BigInteger) et avec des valeurs d'octets négatives (contrairement à Byte.parseByte)

  • Ne convertit pas la chaîne en un char[], ni ne crée des objets StringBuilder et String pour chaque octet unique.

  • Aucune dépendance de bibliothèque qui peut ne pas être disponible

N'hésitez pas à ajouter une vérification d'argument via assertou des exceptions si l'argument n'est pas connu pour être sûr.

Dave L.
la source
2
Pouvez-vous donner un exemple mal décodé ou expliquer en quoi il ne va pas?
Dave L.
5
Cela ne fonctionne pas pour la chaîne "0". Il lève une
exception
49
"0" n'est pas une entrée valide. Les octets nécessitent chacun deux chiffres hexidécimaux. Comme le note la réponse, "N'hésitez pas à ajouter la vérification des arguments ... si l'argument n'est pas connu pour être sûr."
Dave L.
12
javax.xml.bind.DatatypeConverter.parseHexBinary (hexString) semble être environ 20% plus rapide que la solution ci-dessus dans mes micro tests (pour tout ce qu'ils valent), ainsi que de lever correctement des exceptions sur une entrée invalide (par exemple, "gg" n'est pas une hexString valide mais renverra -77 en utilisant la solution proposée).
Trevor Freeman
6
@DaedalusAlpha Cela dépend de votre contexte, mais généralement je trouve qu'il vaut mieux échouer rapidement et fort avec de telles choses afin que vous puissiez corriger vos hypothèses plutôt que de retourner silencieusement des données incorrectes.
Dave L.
331

One-liners:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Avertissements :

  • dans Java 9 Jigsaw, cela ne fait plus partie du jeu de racines (par défaut) java.se, il en résultera donc une exception ClassNotFoundException, sauf si vous spécifiez --add-modules java.se.ee (grâce à @ eckes)
  • Non disponible sur Android (merci de l' Fabianavoir noté), mais vous pouvez simplement prendre le code source si votre système manque javax.xmlpour une raison quelconque. Merci à @ d' Bert Regelinkavoir extrait la source.
Vladislav Rastrusny
la source
14
À mon humble avis, cela devrait être la réponse acceptée / top car elle est courte et propre (contrairement à la réponse de @ DaveL) et ne nécessite aucune bibliothèque externe (comme la réponse de skaffman). Aussi, <Entrez une blague usée sur la réinvention du vélo> .
Priidu Neemre
9
la classe datatypeconverter n'est pas disponible dans android par exemple.
Fabian
4
Avertissement: dans Java 9 Jigsaw, cela ne fait plus partie du java.sejeu de racines (par défaut) , il en résultera donc à ClassNotFoundExceptionmoins que vous ne le --add-modules java.se.ee
spécifiiez
2
@dantebarba Je pense que javax.xml.bind.DatatypeConverterfournit déjà une méthode pour l'encodage / décodage des données Base64. Voir parseBase64Binary()et printBase64Binary().
DragShot
2
Pour ajouter aux problèmes avec DataTypeConverter, Java SE 11 a supprimé complètement l'API JAXB et n'est désormais inclus qu'avec Java EE. Vous pouvez également l'ajouter en tant que dépendance Maven, comme suggéré ici: stackoverflow.com/a/43574427/7347751
David Mordigal
79

La classe Hex du codec commun devrait faire cela pour vous.

http://commons.apache.org/codec/

import org.apache.commons.codec.binary.Hex;
...
byte[] decoded = Hex.decodeHex("00A0BF");
// 0x00 0xA0 0xBF
skaffman
la source
6
Cela semble également bon. Voir org.apache.commons.codec.binary.Hex.decodeHex ()
Dave L.
C'etait intéressant. Mais j'ai trouvé leur solution difficile à suivre. At-il des avantages par rapport à ce que vous avez proposé (autre que la vérification du nombre pair de caractères)?
rafraf
38

Vous pouvez maintenant utiliser BaseEncoding dans guavapour ce faire .

BaseEncoding.base16().decode(string);

Pour l'inverser, utilisez

BaseEncoding.base16().encode(bytes);
jontro
la source
27

En fait, je pense que la solution BigInteger est très agréable:

new BigInteger("00A0BF", 16).toByteArray();

Edit: Pas sûr pour les zéros non significatifs , comme l'a noté l'affiche.

Dave L.
la source
Je le pensais aussi au départ. Et merci de l'avoir documenté - je pensais juste que je devrais ... ça a fait des choses étranges bien que je ne comprenais pas vraiment - comme omettre certains 0x00 en tête et aussi mélanger l'ordre de 1 octet dans une chaîne de 156 octets I jouait avec.
rafraf le
2
C'est un bon point pour mener les 0. Je ne suis pas sûr de croire que cela pourrait mélanger l'ordre des octets et je serais très intéressé de le voir démontré.
Dave L.
1
oui, dès que je l'ai dit, je ne me croyais pas non plus :) J'ai comparé le tableau d'octets de BigInteger avec mmyers'fromHexString et (sans 0x00) avec la chaîne incriminée - ils étaient identiques. Le "mélange" s'est produit, mais il se peut que ce soit autre chose. Je regarderai de plus près demain
rafraf
3
Le problème avec BigInteger est qu'il doit y avoir un "bit de signe". Si l'octet de tête a le bit haut défini, le tableau d'octets résultant a un 0 supplémentaire en 1ère position. Mais toujours +1.
Grey
25

One-liners:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Pour ceux d'entre vous intéressés par le code réel derrière les One-liners de FractalizeR (j'en avais besoin puisque javax.xml.bind n'est pas disponible pour Android (par défaut)), cela vient de com.sun.xml.internal.bind. DatatypeConverterImpl.java :

public byte[] parseHexBinary(String s) {
    final int len = s.length();

    // "111" is not a valid hex encoding.
    if( len%2 != 0 )
        throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);

    byte[] out = new byte[len/2];

    for( int i=0; i<len; i+=2 ) {
        int h = hexToBin(s.charAt(i  ));
        int l = hexToBin(s.charAt(i+1));
        if( h==-1 || l==-1 )
            throw new IllegalArgumentException("contains illegal character for hexBinary: "+s);

        out[i/2] = (byte)(h*16+l);
    }

    return out;
}

private static int hexToBin( char ch ) {
    if( '0'<=ch && ch<='9' )    return ch-'0';
    if( 'A'<=ch && ch<='F' )    return ch-'A'+10;
    if( 'a'<=ch && ch<='f' )    return ch-'a'+10;
    return -1;
}

private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

public String printHexBinary(byte[] data) {
    StringBuilder r = new StringBuilder(data.length*2);
    for ( byte b : data) {
        r.append(hexCode[(b >> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}
Bert Regelink
la source
3
DatatypeConverter n'est pas non plus disponible dans Java 9 par défaut. La chose dangereuse est que le code qui l'utilise se compilera sous Java 1.8 ou version antérieure (Java 9 avec les paramètres source à une version antérieure), mais obtiendra une exception d'exécution sous Java 9 sans "--add-modules java.se.ee".
Stephen M - en grève -
24

Le HexBinaryAdapterpermet de rassembler et de démarsaler entre Stringet byte[].

import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public byte[] hexToBytes(String hexString) {
     HexBinaryAdapter adapter = new HexBinaryAdapter();
     byte[] bytes = adapter.unmarshal(hexString);
     return bytes;
}

C'est juste un exemple que j'ai tapé ... Je l'utilise simplement tel quel et je n'ai pas besoin de créer une méthode distincte pour l'utiliser.

GrkEngineer
la source
5
Cela ne fonctionne que si la chaîne d'entrée (hexString) a un nombre pair de caractères. Sinon: exception dans le thread "main" java.lang.IllegalArgumentException: hexBinary doit être de même longueur:
ovdsrn
3
Oh, merci de l'avoir signalé. Un utilisateur ne devrait vraiment pas avoir un nombre impair de caractères car le tableau d'octets est représenté par {0x00,0xA0,0xBf}. Chaque octet a deux chiffres hexadécimaux ou quartets. Ainsi, tout nombre d'octets doit toujours avoir un nombre pair de caractères. Merci d'avoir mentionné cela.
GrkEngineer
8
Vous pouvez utiliser java.xml.bind.DatatypeConverter.parseHexBinary (hexString) directement au lieu d'utiliser HexBinaryAdapter (qui à son tour appelle DatatypeConverter). De cette façon, vous n'avez pas besoin de créer un objet d'instance d'adaptateur (car les méthodes DatatypeConverter sont statiques).
Trevor Freeman
javax.xml.bind. * n'est plus disponible en Java 9. Ce qui est dangereux, c'est que le code qui l'utilise se compile sous Java 1.8 ou version antérieure (Java 9 avec les paramètres source à antérieur), mais obtient une exception d'exécution sous Java 9.
Stephen M - en grève -
15

Voici une méthode qui fonctionne réellement (basée sur plusieurs réponses semi-correctes précédentes):

private static byte[] fromHexString(final String encoded) {
    if ((encoded.length() % 2) != 0)
        throw new IllegalArgumentException("Input string must contain an even number of characters");

    final byte result[] = new byte[encoded.length()/2];
    final char enc[] = encoded.toCharArray();
    for (int i = 0; i < enc.length; i += 2) {
        StringBuilder curr = new StringBuilder(2);
        curr.append(enc[i]).append(enc[i + 1]);
        result[i/2] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

Le seul problème possible que je peux voir est si la chaîne d'entrée est extrêmement longue; l'appel à toCharArray () crée une copie du tableau interne de la chaîne.

EDIT: Oh, et au fait, les octets sont signés en Java, donc votre chaîne d'entrée est convertie en [0, -96, -65] au lieu de [0, 160, 191]. Mais vous le saviez probablement déjà.

Michael Myers
la source
1
Merci Michael - vous sauvez la vie! Travailler sur un projet BlackBerry et essayer de reconvertir une représentation sous forme de chaîne d'un octet en octet ... en utilisant la méthode "Byte.parseByte (byteString, 16)" de RIM. Le lancement d'un NumberFormatExcpetion a été maintenu. J'ai passé des heures à tyranniser pour comprendre pourquoi. Votre suggestion de "Integer.praseInt ()" a fait l'affaire. Merci encore!!
BonanzaDriver
12

Dans Android, si vous travaillez avec hexadécimal, vous pouvez essayer okio .

utilisation simple:

byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();

et le résultat sera

[-64, 0, 6, 0, 0]
Miao1007
la source
J'ai testé de nombreuses méthodes différentes, mais celle-ci est au moins deux fois plus rapide!
poby
5

La BigInteger()méthode de java.math est très lente et déconseillée.

Integer.parseInt(HEXString, 16)

peut causer des problèmes avec certains caractères sans convertir en chiffre / entier

une bonne méthode de travail:

Integer.decode("0xXX") .byteValue()

Une fonction:

public static byte[] HexStringToByteArray(String s) {
    byte data[] = new byte[s.length()/2];
    for(int i=0;i < s.length();i+=2) {
        data[i/2] = (Integer.decode("0x"+s.charAt(i)+s.charAt(i+1))).byteValue();
    }
    return data;
}

Amusez-vous, bonne chance

Tireur d'élite
la source
4

EDIT: comme indiqué par @mmyers, cette méthode ne fonctionne pas sur les entrées qui contiennent des sous-chaînes correspondant aux octets avec le bit le plus élevé ("80" - "FF"). L'explication se trouve au bogue ID: 6259307 Byte.parseByte ne fonctionnant pas comme annoncé dans la documentation du SDK .

public static final byte[] fromHexString(final String s) {
    byte[] arr = new byte[s.length()/2];
    for ( int start = 0; start < s.length(); start += 2 )
    {
        String thisByte = s.substring(start, start+2);
        arr[start/2] = Byte.parseByte(thisByte, 16);
    }
    return arr;
}
Blair Conrad
la source
1
Fermez, mais cette méthode échoue sur l'entrée donnée "00A0BBF". Voir bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307 .
Michael Myers
1
Également étrangement, il ne traite pas du "9C"
rafraf le
1
@mmyers: whoa. Ce n'est pas bon. Désolé pour la confusion. @ravigad: 9C a le même problème car dans ce cas, le bit haut est défini.
Blair Conrad le
(byte) Short.parseShort (thisByte, 16) résout ce problème
Jamey Hicks
3

Pour ce que ça vaut, voici une autre version qui prend en charge les chaînes de longueur impaire, sans recourir à la concaténation de chaînes.

public static byte[] hexStringToByteArray(String input) {
    int len = input.length();

    if (len == 0) {
        return new byte[] {};
    }

    byte[] data;
    int startIdx;
    if (len % 2 != 0) {
        data = new byte[(len / 2) + 1];
        data[0] = (byte) Character.digit(input.charAt(0), 16);
        startIdx = 1;
    } else {
        data = new byte[len / 2];
        startIdx = 0;
    }

    for (int i = startIdx; i < len; i += 2) {
        data[(i + 1) / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4)
                + Character.digit(input.charAt(i+1), 16));
    }
    return data;
}
Conor Svensson
la source
2

J'ai toujours utilisé une méthode comme

public static final byte[] fromHexString(final String s) {
    String[] v = s.split(" ");
    byte[] arr = new byte[v.length];
    int i = 0;
    for(String val: v) {
        arr[i++] =  Integer.decode("0x" + val).byteValue();

    }
    return arr;
}

cette méthode se divise sur des valeurs hexadécimales séparées par des espaces, mais il ne serait pas difficile de diviser la chaîne sur d'autres critères tels que des groupements de deux caractères.

pfranza
la source
La concaténation de chaînes n'est pas nécessaire. Utilisez simplement Integer.valueOf (val, 16).
Michael Myers
J'ai essayé d'utiliser les conversions radix comme ça auparavant et j'ai eu des résultats mitigés
pfranza
merci - bizarrement, cela fonctionne bien avec cette chaîne: "9C001C" ou "001C21" et échoue avec celui-ci: "9C001C21" Exception dans le thread "main" java.lang.NumberFormatException: Pour la chaîne d'entrée: "9C001C21" à java.lang. NumberFormatException.forInputString (Source inconnue)
rafraf
(Ce n'est pas plus étrange que dans le cas Byte/ byte: bit le plus élevé défini sans
interligne
2

J'aime la solution Character.digit, mais voici comment je l'ai résolue

public byte[] hex2ByteArray( String hexString ) {
    String hexVal = "0123456789ABCDEF";
    byte[] out = new byte[hexString.length() / 2];

    int n = hexString.length();

    for( int i = 0; i < n; i += 2 ) {
        //make a bit representation in an int of the hex value 
        int hn = hexVal.indexOf( hexString.charAt( i ) );
        int ln = hexVal.indexOf( hexString.charAt( i + 1 ) );

        //now just shift the high order nibble and add them together
        out[i/2] = (byte)( ( hn << 4 ) | ln );
    }

    return out;
}
Panique du noyau
la source
2

Le Code présenté par Bert Regelink ne fonctionne tout simplement pas. Essayez ce qui suit:

import javax.xml.bind.DatatypeConverter;
import java.io.*;

public class Test
{  
    @Test
    public void testObjectStreams( ) throws IOException, ClassNotFoundException
    {     
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);

            String stringTest = "TEST";
            oos.writeObject( stringTest );

            oos.close();
            baos.close();

            byte[] bytes = baos.toByteArray();
            String hexString = DatatypeConverter.printHexBinary( bytes);
            byte[] reconvertedBytes = DatatypeConverter.parseHexBinary(hexString);

            assertArrayEquals( bytes, reconvertedBytes );

            ByteArrayInputStream bais = new ByteArrayInputStream(reconvertedBytes);
            ObjectInputStream ois = new ObjectInputStream(bais);

            String readString = (String) ois.readObject();

            assertEquals( stringTest, readString);
        }
    }
Sean Coffey
la source
2
C'est vraiment un problème différent, et appartient probablement à un autre thread.
Sean Coffey
1

J'ai trouvé que Kernel Panic avait la solution la plus utile pour moi, mais j'ai rencontré des problèmes si la chaîne hexadécimale était un nombre impair. résolu de cette façon:

boolean isOdd(int value)
{
    return (value & 0x01) !=0;
}

private int hexToByte(byte[] out, int value)
{
    String hexVal = "0123456789ABCDEF"; 
    String hexValL = "0123456789abcdef";
    String st = Integer.toHexString(value);
    int len = st.length();
    if (isOdd(len))
        {
        len+=1; // need length to be an even number.
        st = ("0" + st);  // make it an even number of chars
        }
    out[0]=(byte)(len/2);
    for (int i =0;i<len;i+=2)
    {
        int hh = hexVal.indexOf(st.charAt(i));
            if (hh == -1)  hh = hexValL.indexOf(st.charAt(i));
        int lh = hexVal.indexOf(st.charAt(i+1));
            if (lh == -1)  lh = hexValL.indexOf(st.charAt(i+1));
        out[(i/2)+1] = (byte)((hh << 4)|lh);
    }
    return (len/2)+1;
}

J'ajoute un certain nombre de nombres hexadécimaux à un tableau, donc je passe la référence au tableau que j'utilise, et l'int dont j'ai besoin converti et renvoyant la position relative du numéro hexadécimal suivant. Ainsi, le tableau d'octets final a [0] nombre de paires hexadécimales, [1 ...] paires hexadécimales, puis le nombre de paires ...

Clayton Balabanov
la source
1

Sur la base de la solution votée par les opérateurs, les éléments suivants devraient être un peu plus efficaces:

  public static byte [] hexStringToByteArray (final String s) {
    if (s == null || (s.length () % 2) == 1)
      throw new IllegalArgumentException ();
    final char [] chars = s.toCharArray ();
    final int len = chars.length;
    final byte [] data = new byte [len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
    }
    return data;
  }

Parce que: la conversion initiale en tableau char épargne les vérifications de longueur dans charAt

Philip Helger
la source
1

Si vous avez une préférence pour les flux Java 8 comme style de codage, cela peut être obtenu en utilisant uniquement des primitives JDK.

String hex = "0001027f80fdfeff";

byte[] converted = IntStream.range(0, hex.length() / 2)
    .map(i -> Character.digit(hex.charAt(i * 2), 16) << 4 | Character.digit(hex.charAt((i * 2) + 1), 16))
    .collect(ByteArrayOutputStream::new,
             ByteArrayOutputStream::write,
             (s1, s2) -> s1.write(s2.toByteArray(), 0, s2.size()))
    .toByteArray();

Les , 0, s2.size()paramètres de la fonction de concaténation du collecteur peuvent être omis si cela ne vous dérange pas d'attraper IOException.

Andy Brown
la source
0
public static byte[] hex2ba(String sHex) throws Hex2baException {
    if (1==sHex.length()%2) {
        throw(new Hex2baException("Hex string need even number of chars"));
    }

    byte[] ba = new byte[sHex.length()/2];
    for (int i=0;i<sHex.length()/2;i++) {
        ba[i] = (Integer.decode(
                "0x"+sHex.substring(i*2, (i+1)*2))).byteValue();
    }
    return ba;
}
David V
la source
0

Ma solution formelle:

/**
 * Decodes a hexadecimally encoded binary string.
 * <p>
 * Note that this function does <em>NOT</em> convert a hexadecimal number to a
 * binary number.
 *
 * @param hex Hexadecimal representation of data.
 * @return The byte[] representation of the given data.
 * @throws NumberFormatException If the hexadecimal input string is of odd
 * length or invalid hexadecimal string.
 */
public static byte[] hex2bin(String hex) throws NumberFormatException {
    if (hex.length() % 2 > 0) {
        throw new NumberFormatException("Hexadecimal input string must have an even length.");
    }
    byte[] r = new byte[hex.length() / 2];
    for (int i = hex.length(); i > 0;) {
        r[i / 2 - 1] = (byte) (digit(hex.charAt(--i)) | (digit(hex.charAt(--i)) << 4));
    }
    return r;
}

private static int digit(char ch) {
    int r = Character.digit(ch, 16);
    if (r < 0) {
        throw new NumberFormatException("Invalid hexadecimal string: " + ch);
    }
    return r;
}

Est similaire à la fonction PHP hex2bin () mais en style Java.

Exemple:

String data = new String(hex2bin("6578616d706c65206865782064617461"));
// data value: "example hex data"
Daniel De León
la source
0

En retard à la fête, mais j'ai fusionné la réponse ci-dessus de DaveL dans une classe avec l'action inverse - juste au cas où cela aiderait.

public final class HexString {
    private static final char[] digits = "0123456789ABCDEF".toCharArray();

    private HexString() {}

    public static final String fromBytes(final byte[] bytes) {
        final StringBuilder buf = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            buf.append(HexString.digits[(bytes[i] >> 4) & 0x0f]);
            buf.append(HexString.digits[bytes[i] & 0x0f]);
        }
        return buf.toString();
    }

    public static final byte[] toByteArray(final String hexString) {
        if ((hexString.length() % 2) != 0) {
            throw new IllegalArgumentException("Input string must contain an even number of characters");
        }
        final int len = hexString.length();
        final byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }
}

Et classe de test JUnit:

public class TestHexString {

    @Test
    public void test() {
        String[] tests = {"0FA1056D73", "", "00", "0123456789ABCDEF", "FFFFFFFF"};

        for (int i = 0; i < tests.length; i++) {
            String in = tests[i];
            byte[] bytes = HexString.toByteArray(in);
            String out = HexString.fromBytes(bytes);
            System.out.println(in); //DEBUG
            System.out.println(out); //DEBUG
            Assert.assertEquals(in, out);

        }

    }

}
DrPhill
la source
0

Je sais que c'est un fil très ancien, mais j'aime quand même ajouter mon centime.

Si j'ai vraiment besoin de coder une simple chaîne hexadécimale en convertisseur binaire, je voudrais le faire comme suit.

public static byte[] hexToBinary(String s){

  /*
   * skipped any input validation code
   */

  byte[] data = new byte[s.length()/2];

  for( int i=0, j=0; 
       i<s.length() && j<data.length; 
       i+=2, j++)
  {
     data[j] = (byte)Integer.parseInt(s.substring(i, i+2), 16);
  }

  return data;
}
tigrou
la source
0

De loin pas la solution la plus propre. Mais cela fonctionne pour moi et est bien formaté:

private String createHexDump(byte[] msg, String description) {
    System.out.println();
    String result = "\n" + description;
    int currentIndex = 0;
    int printedIndex = 0;
    for(int i=0 ; i<msg.length ; i++){
        currentIndex++;
        if(i == 0){
            result += String.format("\n  %04x ", i);
        }
        if(i % 16 == 0 && i != 0){
            result += " | ";
            for(int j=(i-16) ; j<msg.length && j<i ; j++) {
                char characterToAdd = (char) msg[j];
                if (characterToAdd == '\n') {
                    characterToAdd = ' ';
                }
                result += characterToAdd;
                printedIndex++;
            }

            result += String.format("\n  %04x ", i);
        }

        result += String.format("%02x ", msg[i]);
    }

    if(currentIndex - printedIndex > 0){
        int leftOvers = currentIndex - printedIndex;
        for(int i=0 ; i<16-leftOvers ; i++){
            result += "   ";
        }

        result += " | ";

        for(int i=msg.length-leftOvers ; i<msg.length ; i++){
            char characterToAdd = (char) msg[i];
            if (characterToAdd == '\n') {
                characterToAdd = ' ';
            }
            result += characterToAdd;
        }
    }

    result += "\n";

    return result;
}

Le résultat:

  S -> C
    0000 0b 00 2e 06 4d 6f 72 69 74 7a 53 6f 6d 65 20 54  |  .Heyyy Some T
    0010 43 50 20 73 74 75 66 66 20 49 20 63 61 70 74 75  | CP stuff I captu
    0020 72 65 64 2e 2e 77 65 6c 6c 20 66 6f 72 6d 61 74  | red..well format
    0030 3f                                               | ?
Moritz Schmidt
la source
-2

Je pense qu'il le fera pour vous. Je l'ai bricolé à partir d'une fonction similaire qui a renvoyé les données sous forme de chaîne:

private static byte[] decode(String encoded) {
    byte result[] = new byte[encoded/2];
    char enc[] = encoded.toUpperCase().toCharArray();
    StringBuffer curr;
    for (int i = 0; i < enc.length; i += 2) {
        curr = new StringBuffer("");
        curr.append(String.valueOf(enc[i]));
        curr.append(String.valueOf(enc[i + 1]));
        result[i] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}
Bob King
la source
Tout d'abord, vous ne devriez pas avoir besoin de convertir la chaîne en majuscules. Deuxièmement, il est possible d'ajouter des caractères directement à un StringBuffer, ce qui devrait être beaucoup plus efficace.
Michael Myers
-2

Pour moi, c'était la solution, HEX = "FF01" puis divisé en FF (255) et 01 (01)

private static byte[] BytesEncode(String encoded) {
    //System.out.println(encoded.length());
    byte result[] = new byte[encoded.length() / 2];
    char enc[] = encoded.toUpperCase().toCharArray();
    String curr = "";
    for (int i = 0; i < encoded.length(); i=i+2) {
        curr = encoded.substring(i,i+2);
        System.out.println(curr);
        if(i==0){
            result[i]=((byte) Integer.parseInt(curr, 16));
        }else{
            result[i/2]=((byte) Integer.parseInt(curr, 16));
        }

    }
    return result;
}
Alejandro
la source
Cette question a reçu une réponse depuis un certain temps et a plusieurs bonnes alternatives en place; malheureusement, votre réponse n'apporte aucune valeur significativement améliorée à ce stade.
rfornal