Come convertire un array di byte in una stringa esadecimale in Java?


649

Ho un array di byte riempito con numeri esadecimali e stamparlo in modo semplice è abbastanza inutile perché ci sono molti elementi non stampabili. Quello di cui ho bisogno è l'esatto codice esadecimale sotto forma di:3a5f771c


12
Perché non provarlo prima e mostraci cosa hai. Non hai nulla da perdere e tutto da guadagnare. Integer ha un toHexString(...)metodo che può aiutare se questo è quello che stai cercando. Inoltre, è String.format(...)possibile eseguire alcuni trucchi di formattazione utilizzando la %2xstringa di codice.
Hovercraft Full Of Eels


"Quello di cui ho bisogno è l'esatto codice esadecimale sotto forma di: 3a5f771c ..." - hai chiesto un modulo esatto, ma non hai fornito un esempio esatto. Seguendo ciò che hai fornito, converti i primi quattro byte in una stringa, quindi concatena le ellissi nella stringa.
jww

1
Con l'aiuto del flusso in Java 8, può essere semplicemente implementato come: stringa statica byteArrayToHex (byte [] a) {return IntStream.range (0, a.length) .mapToObj (i -> String.format ("% 02x ", a [i])) .reduce ((acc, v) -> acc +" "+ v) .get (); }
martedì

Risposte:


901

Dalla discussione qui , e soprattutto questa risposta, questa è la funzione che attualmente uso:

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String 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] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

I miei piccoli benchmark (un milione di byte mille volte, 256 byte 10 milioni di volte) hanno dimostrato che è molto più veloce di qualsiasi altra alternativa, circa la metà del tempo su array lunghi. Rispetto alla risposta da cui l'ho presa, passando a operazioni bit per bit --- come suggerito nella discussione --- ha ridotto del 20% circa il tempo per le lunghe matrici. (Modifica: quando dico che è più veloce delle alternative, intendo il codice alternativo offerto nelle discussioni. Le prestazioni sono equivalenti a Commons Codec, che utilizza un codice molto simile.)

Versione 2k20, rispetto alle stringhe compatte Java 9:

private static final byte[] HEX_ARRAY = "0123456789ABCDEF".toByteArray();
public static String bytesToHex(byte[] bytes) {
    byte[] hexChars = new byte[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars, StandardCharsets.UTF_8);
}

266
Ho appena trovato javax.xml.bind.DataTypeConverter , parte della distribuzione standard. Perché questo non si presenta quando Google questo tipo di problema? Molti strumenti utili, tra cui String printHexBinary(byte[])e byte[] parseHexBinary(String). printHexBinaryè, tuttavia, molto (2x) più lento della funzione in questa risposta. (Ho controllato la fonte; usa un stringBuilder. parseHexBinaryUsa un array.) In realtà, però, per la maggior parte degli scopi è abbastanza veloce e probabilmente lo hai già.
forse WeCouldStealAVan

75
+1 per la risposta poiché Android non ha DataTypeConverter
Vaiden

7
@maybeWeCouldStealAVan: JDK 7 è ora open source. Dovremmo inviare una patch per migliorare le prestazioni printHexBinary?
kevinarpe,

3
@maybeWeCouldStealAVan potresti per favore spiegare come funziona. Seguo per la maggior parte, ma mi piace molto capire cosa sta succedendo quando si utilizza il codice. Grazie!
jjNford,

24
javax.xml.bind.DataTypeConverterviene rimosso da Java 11.
The Impaler,

421

La libreria Codec di Apache Commons ha una classe Hex per fare proprio questo tipo di lavoro.

import org.apache.commons.codec.binary.Hex;

String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );

12
@cytinus - Il mio downvote si è verificato 4 mesi fa, quindi non sono del tutto sicuro di quello che stavo pensando, ma probabilmente mi sono opposto alle dimensioni della libreria. Questa è una piccola funzione all'interno del programma; non è necessario aggiungere una libreria così ingombrante al progetto per eseguirla.
ArtOfWarfare il

6
@ArtOfWarefare Sono d'accordo, quindi al posto import org.apache.commons.codec.*;tuo potresti fareimport org.apache.commons.codec.binary.Hex;
cytinus,

12
@ArtOfWarfare Non sono d'accordo. L'unica cosa terribile è che le librerie dei commons apache non sono incluse di default con JRE e JDK. Ci sono alcune librerie che sono così utili che dovrebbero essere sul tuo percorso di classe per impostazione predefinita, e questa è una di queste.
corsiKa

29
Consiglio vivamente che questa risposta venga scambiata come risposta principale. Votare sempre per utilizzare una libreria open source ben collaudata, performante su codice personalizzato che non migliora.
Dmitriy Likhten,

6
O nel caso in cui usi BouncyCastle ( org.bouncycastle: bcprov-jdk15on ), puoi usare questa classe org.bouncycastle.util.encoders.HexString toHexString(byte[] data)
:,

320

Il metodo javax.xml.bind.DatatypeConverter.printHexBinary(), parte di Java Architecture for XML Binding (JAXB) , era un modo conveniente per convertire una byte[]stringa esadecimale. La DatatypeConverterclasse includeva anche molti altri utili metodi di manipolazione dei dati.

In Java 8 e precedenti, JAXB faceva parte della libreria standard Java. È stato deprecato con Java 9 e rimosso con Java 11 , come parte dello sforzo di spostare tutti i pacchetti Java EE nelle proprie librerie. È una lunga storia . Ora javax.xml.bindnon esiste e se si desidera utilizzare JAXB, che contiene DatatypeConverter, è necessario installare l' API JAXB e JAXB Runtime da Maven.

Esempio di utilizzo:

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

Si tradurrà in:

000086003D

Questa risposta è uguale a questa .


13
Una buona soluzione, sebbene purtroppo non valida in Android.
Kazriko,

@Kazriko forse vuoi leggere code.google.com/p/dalvik/wiki/JavaxPackages . È un modo per ottenere lezioni di javax su Android. Ma se vuoi solo convertire in esadecimale, non vale la pena.
PhoneixS,

13
DatatypeConverter non è più accessibile a partire da JDK 9
pmcollins

3
@PhoneixS È ancora lì, ma non fa parte del runtime predefinito (a causa dei moduli Java 9).
Spotlight il

2
non fare affidamento su javax.xml.bind, si compila bene ma non può essere trovato in fase di esecuzione. se lo fai, preparati a gestire java.lang.NoClassDefFoundError
Dmitry

227

Soluzione più semplice, nessuna libreria esterna, nessuna costante di cifre:

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

14
Questo è molto lento, in media 1000 volte più lento (per 162 byte di lunghezza) rispetto a quello nella risposta migliore. Evitare di utilizzare String.Format se le prestazioni sono importanti.
pt123,

8
Forse lento. Va bene per le cose che accadono di tanto in tanto, come il login o simili.
Puntatore Null,

29
Se è lento, e allora? Nel mio caso d'uso è solo per un'istruzione di debug, quindi grazie per questo frammento di codice.
vikingsteve,

8
Riutilizzare una libreria includendo altri file JAR di diverse decine di KB non sarebbe esattamente efficiente se tutto ciò di cui hai bisogno è questa funzione (su alcune piattaforme come Android, l'intero Jar viene incluso nell'applicazione finale). E a volte un codice più breve e più chiaro è meglio quando non sono necessarie prestazioni.
personne3000,

2
@ personne3000 forse, ma in tal caso è necessario il supporto di streaming, non una singola funzione di chiamata. questo è facile da capire e ricordare, e quindi da mantenere.
Maarten Bodewes,

59

Una soluzione Guava, per completezza:

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

Adesso lo hexè "48656c6c6f20776f726c64".


In Guava puoi anche usare new HashCode(bytes).toString().
mfulton26,

1
A partire da Guava 22.0 èHashCode.fromBytes(checksum).toString()
Devstr

43

Questo semplice oneliner funziona per me
String result = new BigInteger(1, inputBytes).toString(16);
EDIT: l'uso di questo rimuoverà gli zeri iniziali, ma ha funzionato per il mio caso d'uso. Grazie @Voicu per averlo segnalato


56
Questo oneliner scende a zero byte iniziali.
Voicu,

@Voicu ... E aggiungerà uno zero iniziale il 50% delle volte.
Maarten Bodewes,

27

Ecco alcune opzioni comuni ordinate dal semplice (one-liner) al complesso (enorme libreria). Se sei interessato alle prestazioni, consulta i micro benchmark di seguito.

Opzione 1: frammento di codice - Semplice

Una soluzione molto semplice è quella di utilizzare la BigIntegerrappresentazione esadecimale:

new BigInteger(1, someByteArray).toString(16)

Si noti che poiché gestisce numeri non stringhe di byte arbitrarie , ometterà gli zeri iniziali - questo potrebbe essere o meno ciò che si desidera (ad es. 000AE3Vs 0AE3per un input di 3 byte). Anche questo è molto lento, circa 100 volte più lento rispetto alla prossima opzione.

Opzione 2: frammento di codice - Avanzato

Ecco uno snippet di codice completo, copia e incollabile che supporta maiuscolo / minuscolo e endianness . È ottimizzato per minimizzare la complessità della memoria e massimizzare le prestazioni e dovrebbe essere compatibile con tutte le moderne versioni di Java (5+).

private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};

public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {

    // our output size will be exactly 2x byte-array length
    final char[] buffer = new char[byteArray.length * 2];

    // choose lower or uppercase lookup table
    final char[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;

    int index;
    for (int i = 0; i < byteArray.length; i++) {
        // for little endian we count from last to first
        index = (byteOrder == ByteOrder.BIG_ENDIAN) ? i : byteArray.length - i - 1;

        // extract the upper 4 bit and look up char (0-A)
        buffer[i << 1] = lookup[(byteArray[index] >> 4) & 0xF];
        // extract the lower 4 bit and look up char (0-A)
        buffer[(i << 1) + 1] = lookup[(byteArray[index] & 0xF)];
    }
    return new String(buffer);
}

public static String encode(byte[] byteArray) {
    return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}

Il codice sorgente completo con licenza e decoder Apache v2 è disponibile qui .

Opzione 3: utilizzo di una piccola libreria ottimizzata: bytes-java

Mentre lavoravo al mio precedente progetto, ho creato questo piccolo toolkit per lavorare con byte in Java. Non ha dipendenze esterne ed è compatibile con Java 7+. Include, tra gli altri, un en / decoder HEX molto veloce e ben collaudato:

import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()

Puoi verificarlo su Github: bytes-java .

Opzione 4: Apache Commons Codec

Naturalmente ci sono i buoni vecchi codec comuni . ( avviso di avviso in anticipo ) Mentre stavo lavorando al progetto descritto sopra ho analizzato il codice e sono rimasto piuttosto deluso; molti duplicati di codice non organizzato, codec obsoleti ed esotici probabilmente utili solo per pochissime e abbastanza ingegnerizzate e lente implementazioni di codec popolari (in particolare Base64). Pertanto, prenderei una decisione informata se desideri utilizzarla o un'alternativa. Comunque, se vuoi ancora usarlo, ecco uno snippet di codice:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));

Opzione 5: Google Guava

Molto spesso hai già Guava come dipendenza. In tal caso basta usare:

import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);

Opzione 6: Spring Security

Se si utilizza il framework Spring con Spring Security è possibile utilizzare quanto segue:

import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));

Opzione 7: Castello gonfiabile

Se usi già il framework di sicurezza Bouncy Castle puoi usare il suo Hexutil:

import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);

Opzione 8: compatibilità con Java 9+ o "Non utilizzare JAXBs javax / xml / bind / DatatypeConverter"

Nelle precedenti versioni Java (8 e precedenti) il codice Java per JAXB era incluso come dipendenza del runtime. Poiché la modularizzazione di Java 9 e Jigsaw, il codice non può accedere ad altro codice al di fuori del modulo senza una dichiarazione esplicita. Quindi fai attenzione se ricevi un'eccezione come:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

durante l'esecuzione su una JVM con Java 9+. In tal caso, passa alle implementazioni in una delle alternative sopra. Vedi anche questa domanda .


Micro benchmark

Ecco i risultati di un semplice micro benchmark JMH che codifica array di byte di dimensioni diverse . I valori sono operazioni al secondo, quindi maggiore è meglio. Nota che i micro benchmark molto spesso non rappresentano il comportamento del mondo reale, quindi prendi questi risultati con un granello di sale.

| Name (ops/s)         |    16 byte |    32 byte |  128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1: BigInteger     |  2,088,514 |  1,008,357 |   133,665 |       4 |
| Opt2/3: Bytes Lib    | 20,423,170 | 16,049,841 | 6,685,522 |     825 |
| Opt4: Apache Commons | 17,503,857 | 12,382,018 | 4,319,898 |     529 |
| Opt5: Guava          | 10,177,925 |  6,937,833 | 2,094,658 |     257 |
| Opt6: Spring         | 18,704,986 | 13,643,374 | 4,904,805 |     601 |
| Opt7: BC             |  7,501,666 |  3,674,422 | 1,077,236 |     152 |
| Opt8: JAX-B          | 13,497,736 |  8,312,834 | 2,590,940 |     346 |

Specifiche: JDK 8u202, i7-7700K, Win10, 24GB Ram. Vedi il benchmark completo qui .



21

Vorrei usare qualcosa del genere per una lunghezza fissa, come gli hash:

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

2
Grazie, questo è così conciso e appropriato.
Deepan Prabhu Babu,

18

Ho trovato tre modi diversi qui: http://www.rgagnon.com/javadetails/java-0596.html

Il più elegante, come osserva anche, penso sia questo:

static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
    if ( raw == null ) {
        return null;
    }
    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();
}

Altri metodi erano in esecuzione sul mio campione a 64 byte in 5ms, questo viene eseguito in 0ms. Probabilmente la cosa migliore per mancanza di altre funzioni String come il formato.
Joseph Lust,

if (raw == null) return nullnon fallisce velocemente. Perché mai dovresti usare una nullchiave?
Maarten Bodewes,

Suppongo sia un'abitudine inserire input validate. In questo caso, impediamo qualsiasi eccezione di riferimento Null e lasciamo al chiamante la gestione dei dati errati.
Michael Bisbjerg,

16

A un costo minore di memorizzazione della tabella di ricerca questa implementazione è semplice e molto veloce.

 private static final char[] BYTE2HEX=(
    "000102030405060708090A0B0C0D0E0F"+
    "101112131415161718191A1B1C1D1E1F"+
    "202122232425262728292A2B2C2D2E2F"+
    "303132333435363738393A3B3C3D3E3F"+
    "404142434445464748494A4B4C4D4E4F"+
    "505152535455565758595A5B5C5D5E5F"+
    "606162636465666768696A6B6C6D6E6F"+
    "707172737475767778797A7B7C7D7E7F"+
    "808182838485868788898A8B8C8D8E8F"+
    "909192939495969798999A9B9C9D9E9F"+
    "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
    "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
    "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
    "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
    "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
    "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
   ; 

  public static String getHexString(byte[] bytes) {
    final int len=bytes.length;
    final char[] chars=new char[len<<1];
    int hexIndex;
    int idx=0;
    int ofs=0;
    while (ofs<len) {
      hexIndex=(bytes[ofs++] & 0xFF)<<1;
      chars[idx++]=BYTE2HEX[hexIndex++];
      chars[idx++]=BYTE2HEX[hexIndex];
    }
    return new String(chars);
  }

6
Perché non inizializzare l' BYTE2HEXarray con un semplice forciclo?
Icza,

@icza È possibile anche con un campo finale statico (aka costante)?
nevelis,

1
@nevelis Può essere assegnato in un static { }blocco.
マ ル ち ゃ ん だ よ

1
@icza perché è più veloce codificare una tabella di ricerca piuttosto che generarla. Qui la complessità della memoria viene scambiata con la complessità temporale, cioè. ha bisogno di più memoria ma più veloce (ogni tanto leggermente alle due estremità)
Patrick Favre,

8

Cosa ne pensi di questo?

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

3

Non è necessario utilizzare alcuna libreria esterna o scrivere codice basato su loop e costanti.
Basta solo questo:

byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);

1
Questo è molto simile a EverconfusedGuy's Answer.
Scratte il

2

Preferisco usare questo:

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

È un adattamento leggermente più flessibile della risposta accettata. Personalmente, mantengo insieme sia la risposta accettata che questo sovraccarico, utilizzabile in più contesti.


La domanda originale era per byte [] su String. Guarda esadecimale in byte [] o fai una domanda diversa, @NonExistent.
Bamaco,

2

Di solito uso il seguente metodo per la dichiarazione debuf, ma non so se sia il modo migliore per farlo o meno

private static String digits = "0123456789abcdef";

public static String toHex(byte[] data){
    StringBuffer buf = new StringBuffer();
    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.toString();
}

2
Se il vostro debuffer ha una brutta giornata, provare cluing in StringBuilder esemplificazione con un numero di caratteri da supporto: StringBuilder buf = new StringBuilder(data.length * 2);.
Barbarossa

2

Ok, ci sono molti modi per farlo, ma se decidi di usare una libreria ti suggerirei di cercare nel tuo progetto per vedere se qualcosa è stato implementato in una libreria che è già parte del tuo progetto prima di aggiungere una nuova libreria solo per fare questo. Ad esempio se non lo hai già fatto

org.apache.commons.codec.binary.Hex

forse hai ...

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


2

Se si utilizza il framework Spring Security, è possibile utilizzare:

import org.springframework.security.crypto.codec.Hex

final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));

2

L'aggiunta di un jar di utilità per una funzione semplice non è una buona opzione. Invece assemblare le proprie classi di utilità. di seguito è possibile un'implementazione più rapida.

public class ByteHex {

    public static int hexToByte(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 String[] byteToHexTable = 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"
    };

    private static final String[] byteToHexTableLowerCase = 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 byteToHexTable[b & 0xFF];
    }

    public static String byteToHex(byte[] bytes){
        if(bytes == null) return null;
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
        return sb.toString();
    }

    public static String byteToHex(short[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
        return sb.toString();
    }

    public static String byteToHexLowerCase(byte[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
        return sb.toString();
    }

    public static byte[] hexToByte(String hexString) {
        if(hexString == null) return null;
        byte[] byteArray = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
        }
        return byteArray;
    }

    public static byte hexPairToByte(char ch1, char ch2) {
        return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
    }


}

1

Una piccola variante della soluzione proposta da @maybewecouldstealavan, che consente di raggruppare visivamente N byte nella stringa esadecimale di output:

 final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 final static char BUNDLE_SEP = ' ';

public static String bytesToHexString(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 String(hexChars).trim();    
}

Questo è:

bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E

bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E

1

Non riesco a trovare alcuna soluzione in questa pagina che non lo fa

  1. Usa un ciclo
  2. Usa javax.xml.bind.DatatypeConverter che compila bene ma spesso genera java.lang.NoClassDefFoundError in fase di esecuzione.

Ecco una soluzione che non ha i difetti sopra (nessuna promessa la mia non ha altri difetti però)

import java.math.BigInteger;

import static java.lang.System.out;
public final class App2 {
    // | proposed solution.
    public static String 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 String format = "%0" + evenLength + "x";         
        final String result = String.format (format, new BigInteger(bytes));

        return result;
    }

    public static void main(String[] 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()));
    }
}   

Non sono riuscito a ottenere questo con 62 codici operativi, ma se riesci a vivere senza 0 padding nel caso in cui il primo byte sia inferiore a 0x10, la seguente soluzione utilizza solo 23 codici operativi. Mostra davvero come le soluzioni "facili da implementare" come "pad con uno zero se la lunghezza della stringa è dispari" possono diventare piuttosto costose se un'implementazione nativa non è già disponibile (o in questo caso, se BigInteger aveva un'opzione per il prefisso con zeri in accordare).

public static String 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).toString(16);
}

1

La mia soluzione si basa sulla soluzione di forse WeCouldStealAVan, ma non si basa su alcuna tabella di ricerca allocata in aggiunta. Non utilizza alcun hack di cast "int-to-char" (in realtà, lo Character.forDigit()fa, eseguendo alcuni confronti per verificare quale sia veramente la cifra) e quindi potrebbe essere un po 'più lento. Sentiti libero di usarlo dove vuoi. Saluti.

public static String 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 String(container);
}

0

// Lo spostamento dei byte è più efficiente // Puoi usare anche questo

public static String getHexString (String s) 
{
    byte[] buf = s.getBytes();

    StringBuffer sb = new StringBuffer();

    for (byte b:buf)
    {
        sb.append(String.format("%x", b));
    }


        return sb.toString();
}

0

Se stai cercando un array di byte esattamente come questo per Python, ho convertito questa implementazione Java in 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=[])

0
  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;
  } 

0

Ecco java.util.Base64un'implementazione simile (parziale), non è carina?

public class Base16/*a.k.a. 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 String encode(byte[] data){
            char[] value=new char[data.length*2];
            char[] toHex=upper?toUpperHex:toLowerHex;
            for(int i=0,j=0;i<data.length;i++){
                int octet=data[i]&0xFF;
                value[j++]=toHex[octet>>4];
                value[j++]=toHex[octet&0xF];
            }
            return new String(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;
    }
    //...
}

0
private static String bytesToHexString(byte[] bytes, int length) {
        if (bytes == null || length == 0) return null;

        StringBuilder ret = new StringBuilder(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.toString();
    }

0
Converts bytes data to hex characters

@param bytes byte array to be converted to hex string
@return byte String in hex format

private static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
        v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.