Comment convertir un tableau d’octets en chaîne hexadécimale en Java?

J’ai un tableau d’octets rempli de nombres hexadécimaux et son impression est simple, car il y a beaucoup d’éléments non imprimables. Ce dont j’ai besoin est le code hexadécimal exact sous la forme de: 3a5f771c

    De la discussion ici , et surtout de cette réponse, voici la fonction que j’utilise actuellement:

     private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); public static Ssortingng bytesToHex(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 Ssortingng(hexChars); } 

    Mes propres petits tests (un million d’octets mille fois, 256 octets 10 millions de fois) ont montré qu’il était beaucoup plus rapide que toute autre alternative, environ la moitié du temps sur les tableaux longs. Par rapport à la réponse que j’ai reçue, passer aux opérations binarys – comme suggéré dans la discussion – réduit d’environ 20% le temps consacré aux tableaux longs. (Edit: Quand je dis que c’est plus rapide que les alternatives, je veux dire le code alternatif proposé dans les discussions. Performance est équivalent à Commons Codec, qui utilise un code très similaire.)

    La bibliothèque Apache Commons Codec a une classe Hex pour faire ce type de travail.

     import org.apache.commons.codec.binary.Hex; Ssortingng foo = "I am a ssortingng"; byte[] bytes = foo.getBytes(); System.out.println( Hex.encodeHexSsortingng( bytes ) ); 

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

    Par exemple:

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

    Aura pour résultat:

     000086003D 

    Comme vous pouvez le voir, cela récupérera la chaîne hexadécimale représentant le tableau d’octets avec des zéros non significatifs.

    Cette réponse est fondamentalement la même que dans la question En Java, comment convertir un tableau d’octets en une chaîne de chiffres hexadécimaux tout en conservant des zéros?

    Solution la plus simple, pas de librairie externe, pas de constantes de chiffres:

     public static Ssortingng byteArrayToHex(byte[] a) { SsortingngBuilder sb = new SsortingngBuilder(a.length * 2); for(byte b: a) sb.append(Ssortingng.format("%02x", b)); return sb.toSsortingng(); } 

    Une solution Guava, pour être complet:

     import com.google.common.io.BaseEncoding; ... byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8); final Ssortingng hex = BaseEncoding.base16().lowerCase().encode(bytes); 

    Maintenant, hex est "48656c6c6f20776f726c64" .

    Ce simple oneliner travaille pour moi
    Ssortingng result = new BigInteger(1, inputBytes).toSsortingng(16);
    EDIT – Utiliser ceci va supprimer les zéros en tête, mais ils ont travaillé pour mon cas d’utilisation. Merci @Voicu de l’avoir signalé

    Utilisez la classe DataTypeConverter javax.xml.bind.DataTypeConverter

    Ssortingng hexSsortingng = DatatypeConverter.printHexBinary(bytes[] raw);

    J’ai trouvé trois façons différentes ici: http://www.rgagnon.com/javadetails/java-0596.html

    Le plus élégant, comme il le note aussi, je pense que c’est celui-ci:

     static final Ssortingng HEXES = "0123456789ABCDEF"; public static Ssortingng getHex( byte [] raw ) { if ( raw == null ) { return null; } final SsortingngBuilder hex = new SsortingngBuilder( 2 * raw.length ); for ( final byte b : raw ) { hex.append(HEXES.charAt((b & 0xF0) >> 4)) .append(HEXES.charAt((b & 0x0F))); } return hex.toSsortingng(); } 

    Au moindre coût de stockage de la table de consultation, cette implémentation est simple et très rapide.

      private static final char[] BYTE2HEX=( "000102030405060708090A0B0C0D0E0F"+ "101112131415161718191A1B1C1D1E1F"+ "202122232425262728292A2B2C2D2E2F"+ "303132333435363738393A3B3C3D3E3F"+ "404142434445464748494A4B4C4D4E4F"+ "505152535455565758595A5B5C5D5E5F"+ "606162636465666768696A6B6C6D6E6F"+ "707172737475767778797A7B7C7D7E7F"+ "808182838485868788898A8B8C8D8E8F"+ "909192939495969798999A9B9C9D9E9F"+ "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+ "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+ "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+ "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+ "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray(); ; public static Ssortingng getHexSsortingng(byte[] bytes) { final int len=bytes.length; final char[] chars=new char[len<<1]; int hexIndex; int idx=0; int ofs=0; while (ofs 

    Je voudrais utiliser quelque chose comme ça pour une longueur fixe, comme des hachages:

     md5sum = Ssortingng.format("%032x", new BigInteger(1, md.digest())); 

    Que dis-tu de ça?

      Ssortingng byteToHex(final byte[] hash) { Formatter formatter = new Formatter(); for (byte b : hash) { formatter.format("%02x", b); } Ssortingng result = formatter.toSsortingng(); formatter.close(); return result; } 

    Je préfère utiliser ceci:

     final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); public static Ssortingng bytesToHex(byte[] bytes, int offset, int count) { char[] hexChars = new char[count * 2]; for ( int j = 0; j < count; j++ ) { int v = bytes[j+offset] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new Ssortingng(hexChars); } 

    Il s’agit d’une adaptation légèrement plus souple de la réponse acceptée. Personnellement, je garde à la fois la réponse acceptée et cette surcharge, utilisable dans plus de contextes.

    J’utilise généralement la méthode suivante pour la déclaration debuf, mais je ne sais pas si c’est la meilleure façon de le faire ou non

     private static Ssortingng digits = "0123456789abcdef"; public static Ssortingng toHex(byte[] data){ SsortingngBuffer buf = new SsortingngBuffer(); for (int i = 0; i != data.length; i++) { int v = data[i] & 0xff; buf.append(digits.charAt(v >> 4)); buf.append(digits.charAt(v & 0xf)); } return buf.toSsortingng(); } 

    Ok, il y a plusieurs façons de le faire, mais si vous décidez d’utiliser une bibliothèque, je suggérerais de fouiller dans votre projet pour voir si quelque chose a été implémenté dans une bibliothèque qui fait déjà partie de votre projet avant d’append une nouvelle bibliothèque. juste pour faire ça. Par exemple si vous n’avez pas déjà

    org.apache.commons.codec.binary.Hex

    peut-être que vous avez …

    org.apache.xerces.impl.dv.util.HexBin

    Une petite variante de la solution proposée par @maybewecouldstealavan, qui permet de regrouper visuellement N octets dans la chaîne hexadécimale de sortie:

      final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); final static char BUNDLE_SEP = ' '; public static Ssortingng bytesToHexSsortingng(byte[] bytes, int bundleSize /*[bytes]*/]) { char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)]; for (int j = 0, k = 1; j < bytes.length; j++, k++) { int v = bytes[j] & 0xFF; int start = (j * 2) + j/bundleSize; hexChars[start] = HEX_ARRAY[v >>> 4]; hexChars[start + 1] = HEX_ARRAY[v & 0x0F]; if ((k % bundleSize) == 0) { hexChars[start + 2] = BUNDLE_SEP; } } return new Ssortingng(hexChars).sortingm(); } 

    C’est:

     bytesToHexSsortingng("..DOOM..".toCharArray().getBytes(), 2); 2E2E 444F 4F4D 2E2E bytesToHexSsortingng("..DOOM..".toCharArray().getBytes(), 4); 2E2E444F 4F4D2E2E 

    Vous ne trouvez pas de solution sur cette page qui ne

    1. Utiliser une boucle
    2. Utilisez javax.xml.bind.DatatypeConverter qui comstack bien mais jette souvent java.lang.NoClassDefFoundError à l’exécution.

    Voici une solution qui n’a pas les défauts ci-dessus (aucune promesse que la mienne n’a pas d’autres failles cependant)

     import java.math.BigInteger; import static java.lang.System.out; public final class App2 { // | proposed solution. public static Ssortingng encode(byte[] bytes) { final int length = bytes.length; // | BigInteger constructor throws if it is given an empty array. if (length == 0) { return "00"; } final int evenLength = (int)(2 * Math.ceil(length / 2.0)); final Ssortingng format = "%0" + evenLength + "x"; final Ssortingng result = Ssortingng.format (format, new BigInteger(bytes)); return result; } public static void main(Ssortingng[] args) throws Exception { // 00 out.println(encode(new byte[] {})); // 01 out.println(encode(new byte[] {1})); //203040 out.println(encode(new byte[] {0x20, 0x30, 0x40})); // 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e out.println(encode("All your base are belong to us.".getBytes())); } } 

    Je ne pouvais pas obtenir cela sous 62 opcodes, mais si vous pouvez vivre sans 0 padding au cas où le premier octet est inférieur à 0x10, la solution suivante utilise seulement 23 opcodes. Montre vraiment comment “facile à mettre en œuvre vous-même” des solutions comme “pad avec un zéro si la longueur de la chaîne est étrange” peut devenir assez cher si une implémentation native n’est pas déjà disponible (ou dans ce cas, si BigInteger avait une option de préfixe avec des zéros dans toSsortingng).

     public static Ssortingng encode(byte[] bytes) { final int length = bytes.length; // | BigInteger constructor throws if it is given an empty array. if (length == 0) { return "00"; } return new BigInteger(bytes).toSsortingng(16); } 

    // Le décalage des octets est plus efficace // Vous pouvez aussi utiliser celui-ci

     public static Ssortingng getHexSsortingng (Ssortingng s) { byte[] buf = s.getBytes(); SsortingngBuffer sb = new SsortingngBuffer(); for (byte b:buf) { sb.append(Ssortingng.format("%x", b)); } return sb.toSsortingng(); } 

    Si vous recherchez un tableau d’octets exactement comme celui-ci pour python, j’ai converti cette implémentation Java en python.

     class ByteArray: @classmethod def char(cls, args=[]): cls.hexArray = "0123456789ABCDEF".encode('utf-16') j = 0 length = (cls.hexArray) if j < length: v = j & 0xFF hexChars = [None, None] hexChars[j * 2] = str( cls.hexArray) + str(v) hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F) # Use if you want... #hexChars.pop() return str(hexChars) array = ByteArray() print array.char(args=[]) 
      public static byte[] hexSsortingngToByteArray(Ssortingng 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; } 

    Voici une implémentation de type java.util.Base64 (partielle), n’est-ce pas joli?

     public class Base16/*aka Hex*/ { public static class Encoder{ private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; private boolean upper; public Encoder(boolean upper) { this.upper=upper; } public Ssortingng encode(byte[] data){ char[] value=new char[data.length*2]; char[] toHex=upper?toUpperHex:toLowerHex; for(int i=0,j=0;i>4]; value[j++]=toHex[octet&0xF]; } return new Ssortingng(value); } static final Encoder LOWER=new Encoder(false); static final Encoder UPPER=new Encoder(true); } public static Encoder getEncoder(){ return Encoder.LOWER; } public static Encoder getUpperEncoder(){ return Encoder.UPPER; } //... } 
     private static Ssortingng bytesToHexSsortingng(byte[] bytes, int length) { if (bytes == null || length == 0) return null; SsortingngBuilder ret = new SsortingngBuilder(2*length); for (int i = 0 ; i < length ; i++) { int b; b = 0x0f & (bytes[i] >> 4); ret.append("0123456789abcdef".charAt(b)); b = 0x0f & bytes[i]; ret.append("0123456789abcdef".charAt(b)); } return ret.toSsortingng(); } 

    Ma solution est basée sur la solution deWeCouldStealAVan, mais ne repose pas sur des tables de recherche supplémentaires. Il n’utilise pas de hacks de type “int-to-char” (en fait, Character.forDigit() fait, en effectuant des comparaisons pour vérifier le caractère réel du chiffre) et peut donc être un peu plus lent. N’hésitez pas à l’utiliser partout où vous voulez. À votre santé.

     public static Ssortingng bytesToHex(final byte[] bytes) { final int numBytes = bytes.length; final char[] container = new char[numBytes * 2]; for (int i = 0; i < numBytes; i++) { final int b = bytes[i] & 0xFF; container[i * 2] = Character.forDigit(b >>> 4, 0x10); container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10); } return new Ssortingng(container); }