Codice Java Per convertire byte in esadecimale


184

Ho una matrice di byte. Voglio che ogni stringa di byte di quell'array sia convertita nei corrispondenti valori esadecimali.

Esiste una funzione in Java per convertire un array di byte in esadecimale?


2
Quello che chiami array di byte in Java è chiamato stringa di byte in altre lingue (ad esempio docs.racket-lang.org/guide/bytestrings.html )
Patrick Favre,

Risposte:


311
    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 "

Guarda anche

  • java.util.Formatter sintassi
    • %[flags][width]conversion
      • Flag '0': il risultato sarà a zero
      • Larghezza 2
      • Conversione 'X': il risultato è formattato come intero esadecimale, maiuscolo

Guardando il testo della domanda, è anche possibile che questo sia ciò che viene richiesto:

    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]"

Qui vengono utilizzate diverse risposte Integer.toHexString(int); questo è fattibile, ma con alcuni avvertimenti. Poiché il parametro è un int, viene eseguita una conversione primitiva allargata byteall'argomento, che comporta l'estensione del segno.

    byte b = -1;
    System.out.println(Integer.toHexString(b));
    // prints "ffffffff"

L'8 bit byte, che è firmato in Java, è esteso a 32 bit int. Per annullare efficacemente questa estensione di segno, si può mascherare bytecon 0xFF.

    byte b = -1;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "ff"

Un altro problema con l'utilizzo toHexStringè che non si riempie di zero:

    byte b = 10;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "a"

Entrambi i fattori combinati dovrebbero rendere la String.formatsoluzione più preferibile.

Riferimenti


@Vivek: che cos'è "un valore enormemente grande"? Qual è l'input e qual è l'output?
poligenelubrificanti,

Lasciami spiegare di nuovo .. Ho una raccolta di stringhe di byte in un array. Ma quello che devo fare è analizzare ogni byte separatamente. Quindi, non voglio lavorare sull'intero array, ma su una singola stringa di byte alla volta, che è un componente di quell'array .. La confusione è nata a causa della parola " Vettore". Ora nel codice seguente "byte bv = 10; String hexString = Integer.toHexString (bv);" CAse 1 (Byte Recieved: 68 Hex Output:: 44) Caso: 2 (Byte Recieved: -46 Output esadecimale:: ffffffd2) ......... Perché sto ottenendo un risultato così inaspettato per alcuni valori?
Vivek,

1
@Vivek: leggi la mia risposta sull'utilizzo toHexString. Devi mascherarlo con & 0xFF, cioè lo Integer.toHexString(-46 & 0xFF)è "d2".
poligenelubrificanti,

@polygenelubricants: Grazie mille .. Sembra, finalmente il codice funziona bene .. È sicuro usare la funzione HexString ora? Oppure potrebbero esserci delle lacune nell'approccio?
Vivek,

1
@Vivek: è "sicuro", devi solo stare attento e assicurarti di mascherare il bytevalore & 0xFFogni volta. la formatsoluzione sopra potrebbe richiedere anche il mascheramento a seconda di cosa stai effettivamente usando come argomento.
poligenilubrificanti,

65

Sto postando perché nessuna delle risposte esistenti spiega perché i loro approcci funzionano, cosa che penso sia davvero importante per questo problema. In alcuni casi, ciò fa apparire la soluzione proposta inutilmente complicata e sottile. Per illustrare fornirò un approccio abbastanza semplice, ma fornirò un po 'più di dettagli per aiutare a illustrare il motivo per cui funziona.

Prima di tutto, cosa stiamo cercando di fare? Vogliamo convertire un valore di byte (o un array di byte) in una stringa che rappresenta un valore esadecimale in ASCII. Quindi il primo passo è scoprire esattamente cos'è un byte in Java:

Il tipo di dati byte è un intero di complemento a due bit con segno a 8 bit . Ha un valore minimo di -128 e un valore massimo di 127 (incluso). Il tipo di dati byte può essere utile per salvare la memoria in array di grandi dimensioni, dove il risparmio di memoria conta davvero. Possono anche essere usati al posto di int dove i loro limiti aiutano a chiarire il tuo codice; il fatto che l'intervallo di una variabile sia limitato può servire come una forma di documentazione.

Cosa significa questo? Alcune cose: prima di tutto, significa che stiamo lavorando con 8 bit . Quindi, ad esempio, possiamo scrivere il numero 2 come 0000 0010. Tuttavia, poiché si tratta del complemento a due, scriviamo un 2 negativo come questo: 1111 1110. Ciò che significa anche che la conversione in esadecimale è molto semplice. Cioè, devi semplicemente convertire ogni segmento a 4 bit direttamente in esadecimale. Nota che per dare un senso ai numeri negativi in ​​questo schema dovrai prima capire il complemento a due. Se non capisci già il complemento a due, puoi leggere un'eccellente spiegazione, qui: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


Conversione del complemento a due in esadecimale in generale

Una volta che un numero è nel complemento a due è assolutamente semplice convertirlo in esadecimale. In generale, la conversione da binario a esadecimale è molto semplice e, come vedrai nei prossimi due esempi, puoi passare direttamente dal complemento a due in esadecimale.

Esempi

Esempio 1: convertire 2 in esadecimale.

1) Innanzitutto converti 2 in binario nel complemento a due:

2 (base 10) = 0000 0010 (base 2)

2) Ora converti binario in esadecimale:

0000 = 0x0 in hex
0010 = 0x2 in hex

therefore 2 = 0000 0010 = 0x02. 

Esempio 2: Converti -2 (in complemento a due) in esadecimale.

1) Prima converti -2 in binario nel complemento a due:

-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) Ora converti in esadecimale:

1111 = 0xF in hex
1110 = 0xE in hex

therefore: -2 = 1111 1110 = 0xFE.


In questo modo in Java

Ora che abbiamo trattato il concetto, scoprirai che possiamo ottenere ciò che vogliamo con un semplice mascheramento e spostamento. La cosa fondamentale da capire è che il byte che stai cercando di convertire è già nel complemento a due. Non fai questa conversione da solo. Penso che questo sia un grande punto di confusione su questo tema. Prendiamo ad esempio il seguente array di byte:

byte[] bytes = new byte[]{-2,2};

Li abbiamo appena convertiti manualmente in esadecimale, sopra, ma come possiamo farlo in Java? Ecco come:

Passaggio 1: creare uno StringBuffer per contenere il nostro calcolo.

StringBuffer buffer = new StringBuffer();

Passaggio 2: isolare i bit di ordine superiore, convertirli in esadecimali e aggiungerli al buffer

Dato il numero binario 1111 1110, possiamo isolare i bit di ordine superiore spostandoli prima di 4, quindi azzerando il resto del numero. Logicamente questo è semplice, tuttavia, i dettagli di implementazione in Java (e in molte lingue) introducono una ruga a causa dell'estensione del segno. In sostanza, quando si sposta un valore byte, Java prima converte il valore in un numero intero, quindi esegue l'estensione del segno. Quindi, mentre ti aspetteresti che 1111 1110 >> 4 sia 0000 1111, in realtà, in Java è rappresentato come il complemento a due 0xFFFFFFFF!

Quindi tornando al nostro esempio:

1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)

Possiamo quindi isolare i bit con una maschera:

1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex. 

In Java possiamo fare tutto questo in un colpo solo:

Character.forDigit((bytes[0] >> 4) & 0xF, 16);

La funzione forDigit mappa semplicemente il numero che lo passi sull'insieme di numeri esadecimali 0-F.

Passaggio 3: Successivamente è necessario isolare i bit di ordine inferiore. Poiché i bit che vogliamo sono già nella posizione corretta, possiamo semplicemente mascherarli:

1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.  

Come prima, in Java possiamo fare tutto questo in un colpo solo:

Character.forDigit((bytes[0] & 0xF), 16);

Mettendo tutto insieme possiamo farlo come un ciclo for e convertire l'intero array:

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

Spero che questa spiegazione renda le cose più chiare per quelli di voi che si chiedono esattamente cosa sta succedendo nei molti esempi che troverete su Internet. Spero di non aver commesso errori eclatanti, ma suggerimenti e correzioni sono i benvenuti!


4
migliore risposta! L'implementazione simmetrica di una stringa esadecimale in byte verrebbe quindi convertita quindi Character.digit(), ad esempio(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn

21

Il modo più veloce che ho ancora trovato per fare questo è il seguente:

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

È ~ 50 volte più veloce di String.format. se vuoi provarlo:

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
        }

    }
}

Modifica : ho appena trovato qualcosa di solo un po 'più veloce e che si mantiene su una riga ma non è compatibile con JRE 9. Utilizzare a proprio rischio

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);

2
DatatypeConverter non è più disponibile in Java 9. La cosa pericolosa è che il codice che lo utilizza verrà compilato in Java 1.8 o precedente (Java 9 con impostazioni di origine precedenti), ma ottiene un'eccezione di runtime in Java 9.
Stephen M -on strike-

Secondo punto @StephenMs: l'utilizzo di questo con jre9 andrà in crash con l'eccezione ClassNotFound
Patrick Favre,

In realtà può semplicemente estrarre il metodo del codice sorgente printHexBinary da src.zip di jdk, che sembra 1 volta più veloce del primo metodo.
Frutta l'

1
Se lavori con array di caratteri per la costante HEXES, invece String e charAt (), ottieni una velocità del 20% maggiore.
Dyorgio,

15

Prova in questo modo:

byte bv = 10;
String hexString = Integer.toHexString(bv);

Trattare con array (se ti ho capito bene):

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

Come menzionato i poligenelubrificanti, String.format()la risposta giusta è paragonabile a Integer.toHexString()(poiché tratta i numeri negativi in ​​modo corretto).


2
Questo firmerà ext, ad esempio provare -1.
poligenelubrificanti,

byte bv = 10; String hexString = Integer.toHexString (bv); Questo sembra funzionare firne .. Posso applicarlo individualmente su ogni elemento dell'array .. L'altro codice (Trattare con array) restituisce un valore troppo grande. Cosa potrebbe esserci per questo motivo?
Vivek,

@Vivek, perché in caso bvrestituisce un singolo carattere esadecimale . Considerando che il resto del codice restituisce una stringa di caratteri esadecimali . Ho modificato il codice con il delimitatore in modo da poterlo capire ora.
0x2D9A3,

@Bar: è ancora possibile utilizzarlo Integer.toHexStringse si maschera il bytecon 0xFFper annullare l'estensione del segno.
poligenelubrificanti,

CAUSA 1 (Byte ricevuto: 68 Uscita esadecimale: 44) Caso: 2 (Byte ricevuto: -46 Uscita esadecimale: ffffffd2) Ricevo valori di output imprevisti in caso di array di byte negativi ... Come gestirlo?
Vivek,

13

La migliore soluzione è questa tosta unita con un solo rivestimento:

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

come menzionato qui


4
DatatypeConverter non è più disponibile in Java 9. La cosa pericolosa è che il codice che lo utilizza verrà compilato in Java 1.8 o precedente (Java 9 con impostazioni di origine precedenti), ma ottiene un'eccezione di runtime in Java 9.
Stephen M -on strike-

Triste quando dici che non è in jdk9. new BigInteger(byteArray).toString(16)è la strada da percorrere allora. Sono problemi perf con quello ??
prayagupd,

Forse non sono problemi perf, ma mancheranno gli zeri iniziali (poiché sono insignificanti per un numero come BigInteger)
Friso,

Sembra che sia ancora nei documenti di Java 9 , quindi sembra che sia ok usarlo ancora da quello che posso dire
Brad Parks

penso che come spiegato qui sia ancora ok da usare per java9, ma verrà rimosso nelle future versioni di Java. sarà anche possibile usarlo con il 'nuovo' modulo jaxb autonomo dalla versione 2.3.0 .
lince

11

Se si desidera una rappresentazione esadecimale a larghezza costante, ovvero 0Aanziché A, in modo da poter recuperare i byte in modo univoco, provare format():

StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
    result.append(String.format("%02X", bb));
}
return result.toString();

11

Un modo breve e semplice per convertire byte[]in stringa esadecimale utilizzando 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

Come funziona?

La classe di java.math.BigIntegerclasse di sistema integrata ( java.math.BigInteger ) è compatibile con i dati binari ed esadecimali:

  • Ha un costruttore BigInteger(signum=1, byte[])per creare un intero grande da byte[](impostare il suo primo parametro signum= 1per gestire correttamente i byte negativi)
  • Utilizzare BigInteger.toString(16)per convertire il numero intero grande in stringa esadecimale
  • Per analizzare un numero esadecimale utilizzare new BigInteger("ffa74b", 16)- non gestisce correttamente lo zero iniziale

Se vuoi avere lo zero iniziale nel risultato esadecimale, controlla la sua dimensione e aggiungi lo zero mancante se necessario:

if (hex.length() % 2 == 1)
    hex = "0" + hex;

Appunti

Utilizzare new BigInteger(1, bytes), invece di new BigInteger(bytes), perché Java è " rotto in base alla progettazione " e il bytetipo di dati non contiene byte ma numeri interi minuscoli firmati [-128 ... 127]. Se il primo byte è negativo, BigIntegerpresuppone che si passi un intero grande negativo. Basta passare 1come primo parametro ( signum=1).

La conversione da hex a hexbyte[] è complicata: a volte uno zero iniziale entra nell'output prodotto e dovrebbe essere pulito in questo modo:

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

L'ultima nota è se se byte[]ha diversi zero iniziali, andranno persi.


1
Se il byte iniziale ha un valore decimale inferiore a 16, otterrai anche una stringa con un numero dispari di caratteri esadecimali.
Alex Jorgenson,

8

Se sei felice di usare una libreria esterna, la org.apache.commons.codec.binary.Hexclasse ha un encodeHexmetodo che accetta a byte[]e restituisce a char[]. Questo metodo è MOLTO più veloce dell'opzione di formattazione e incapsula i dettagli della conversione. Inoltre viene fornito con un decodeHexmetodo per la conversione opposta.


4
Un modo ancora più semplice è utilizzare le funzioni integrate javax.xml.bind.DatatypeConverter / parseHexBinary e printHexBinary. Vedi stackoverflow.com/questions/9655181/…
Alan Thompson,

2
+1 a questa opzione. Hex ha anche un metodo encodeHexString, che accetta un byte [] e restituisce una stringa.
Mingjiang Shi,

non dimenticare che lo javaxspazio dei nomi non è sempre disponibile.
Mene,

7

È possibile utilizzare il metodo dalla libreria del provider Bouncy Castle :

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

Il pacchetto Bouncy Castle Crypto è un'implementazione Java di algoritmi crittografici. Questo vaso contiene il provider JCE e l'API leggera per le API di crittografia Bouncy Castle per JDK da 1,5 a JDK 1,8.

Dipendenza da Maven:

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

o da Apache Commons Codec :

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

Il pacchetto Apache Commons Codec contiene un semplice codificatore e decodificatore per vari formati come Base64 e Hexadecimal. Oltre a questi codificatori e decodificatori ampiamente utilizzati, il pacchetto di codec mantiene anche una raccolta di utilità di codifica fonetica.

Dipendenza da Maven:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>

Sì, questa è la soluzione migliore , ma richiede una libreria esterna: Apache Commons Codec ( mvnrepository.com/artifact/commons-codec/commons-codec/1.11 ) o BouncyCastle Provider ( mvnrepository.com/artifact/org.bouncycastle/bcprov- jdk15on / 1.60 )
Svetlin Nakov

5

Questo è il codice che ho trovato per eseguire il più veloce finora. L'ho eseguito su array di 109015 byte di lunghezza 32, in 23ms. Lo stavo eseguendo su una VM, quindi probabilmente funzionerà più velocemente su bare metal.

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

Quindi puoi semplicemente farlo

String s = new String( encodeHex(myByteArray) );

3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));

Non funziona: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)ritorna"-fdfcfbfb"
Martin Vysny,

È un risultato giusto. Stai lavorando con byte '-1', '2' ... '5'. Ciò significa che i byte non hanno visualiztion ( unicode.org ) se intendi lavorare con i letterali '-1', '2' ... '5' dovresti lavorare con i valori delle stringhe.
Wender,

È un risultato sbagliato. Il valore di byte Java di -1 è in effetti 0xFF (è lo stesso di (int) 255) poiché i byte Java sono firmati, quindi il risultato dovrebbe essere FF02030405. Se provi la soluzione @Jerinaw sopra vedrai che stamperà l'output corretto. Vedi anche la soluzione di Svetlin Nakov di seguito.
Martin Vysny,

2

Ecco una semplice funzione per convertire byte in esadecimali

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

2

Altri hanno trattato il caso generale. Ma se hai una matrice di byte di una forma nota, ad esempio un indirizzo MAC, puoi:

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

1

Creare (e distruggere) un mucchio di Stringistanze non è un buon modo se le prestazioni sono un problema.

Ignora quegli argomenti dettagliati (duplicati) che controllano le dichiarazioni if. Questo è per (un altro) scopo educativo.

Progetto completo maven: http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/

Codifica ...

/**
 * 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);
}

Decodifica ...

/**
 * 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);
}

1

Questo è un modo molto veloce. Non sono necessarie librerie esterne.

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

1

Non riuscivo a capire cosa intendevi esattamente con byte String, ma qui ci sono alcune conversioni da byte a String e viceversa, ovviamente c'è molto di più sulle documentazioni ufficiali

Integer intValue = 149;

Il valore byte corrispondente è:

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

recuperare il valore intero da una variabile Byte:

Integer anInt = byteValue.intValue(); // This will convert the byteValue variable to a signed Integer

Da byte e numero intero a stringa esadecimale:
questo è il modo in cui lo faccio:

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

Conversione di una matrice di byte in una stringa esadecimale:
per quanto ne so non esiste una funzione semplice per convertire tutti gli elementi all'interno di una matrice di alcuni Objectin elementi di un'altra Object, quindi devi farlo da solo. È possibile utilizzare le seguenti funzioni:

Da byte [] a String:

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

E da stringa esadecimale a byte []:

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

È troppo tardi ma spero che questo possa aiutare alcuni altri;)


1

Ecco il tuo metodo veloce:

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

1
brutto, ma probabilmente molto efficiente. :-)
Rich S

1

Proprio come alcune altre risposte, consiglio di usare String.format()e BigInteger. Ma per interpretare l'array di byte come rappresentazione binaria big-endian anziché come rappresentazione binaria a complemento a due (con signum e uso incompleto della gamma di valori esadecimali) utilizzare BigInteger (int signum, byte [] magnitude) , non BigInteger (byte [] val ) .

Ad esempio, per una matrice di byte di lunghezza 8 utilizzare:

String.format("%016X", new BigInteger(1,bytes))

vantaggi:

  • zeri iniziali
  • nessun segno
  • solo funzioni integrate
  • solo una riga di codice

Svantaggio:

  • potrebbero esserci modi più efficienti per farlo

Esempio:

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

Esempio di output:

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

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.