Código Java Para convertir byte a hexadecimal

184

Tengo una matriz de bytes. Quiero que cada cadena de bytes de esa matriz se convierta a sus valores hexadecimales correspondientes.

¿Hay alguna función en Java para convertir una matriz de bytes a hexadecimal?

Vivek
fuente
2
Lo que se llama matriz de bytes en Java se llama cadena de bytes en otros idiomas (por ejemplo, docs.racket-lang.org/guide/bytestrings.html )
Patrick Favre el

Respuestas:

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 "

Ver también

  • java.util.Formatter sintaxis
    • %[flags][width]conversion
      • Indicador '0': el resultado se rellenará con ceros
      • Anchura 2
      • Conversión 'X': el resultado se formatea como un entero hexadecimal, mayúscula

Mirando el texto de la pregunta, también es posible que esto sea lo que se solicita:

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

Varias respuestas aquí utiliza Integer.toHexString(int); Esto es factible, pero con algunas advertencias. Como el parámetro es an int, se realiza una conversión primitiva de ampliación al byteargumento, que implica la extensión del signo.

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

El 8 bits byte, que está firmado en Java, está extendido a 32 bits int. Para deshacer efectivamente esta extensión de signo, se puede enmascarar bytecon 0xFF.

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

Otro problema con el uso toHexStringes que no rellena con ceros:

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

Ambos factores combinados deberían hacer que la String.formatsolución sea más preferible.

Referencias

poligenelubricantes
fuente
@Vivek: ¿qué es "un valor enormemente grande"? ¿Cuál es la entrada y cuál es la salida?
Polygenelubricants
Déjame explicarte de nuevo ... Tengo una colección de cadenas de bytes en una matriz. Pero lo que tengo que hacer es analizar cada byte por separado ... Por lo tanto, no quiero trabajar en toda la matriz, sino en una cadena de bytes individual a la vez, ese es un componente de esa matriz ... La confusión surgió debido a la palabra " formación". Ahora en el código siguiente "byte bv = 10; String hexString = Integer.toHexString (bv);" CAse 1 (Byte recibido: 68 salida hexadecimal: 44) Caso: 2 (byte recibido: -46 salida hexadecimal: ffffffd2) ......... ¿Por qué obtengo un resultado tan inesperado para algunos valores?
Vivek
1
@Vivek: lee mi respuesta sobre el uso toHexString. Tienes que enmascararlo & 0xFF, Integer.toHexString(-46 & 0xFF)es decir, es "d2".
Polygenelubricants
@polygenelubricants: Muchas gracias ... Parece que, finalmente, el código funciona bien ... ¿Es seguro utilizar la función HexString ahora? ¿O puede haber algunas lagunas con el enfoque?
Vivek
1
@Vivek: es "seguro", solo debes tener cuidado y asegurarte de enmascarar el bytevalor & 0xFFcada vez. la formatsolución anterior también puede requerir enmascarar dependiendo de lo que realmente esté usando como argumento.
Polygenelubricants
65

Estoy publicando porque ninguna de las respuestas existentes explica por qué funcionan sus enfoques, lo que creo que es realmente importante para este problema. En algunos casos, esto hace que la solución propuesta parezca innecesariamente complicada y sutil. Para ilustrar, proporcionaré un enfoque bastante sencillo, pero proporcionaré un poco más de detalle para ayudar a ilustrar por qué funciona.

En primer lugar, ¿qué estamos tratando de hacer? Queremos convertir un valor de byte (o una matriz de bytes) en una cadena que represente un valor hexadecimal en ASCII. Entonces, el primer paso es descubrir exactamente qué es un byte en Java:

El tipo de datos de byte es un entero de dos bits con signo de 8 bits . Tiene un valor mínimo de -128 y un valor máximo de 127 (inclusive). El tipo de datos de byte puede ser útil para ahorrar memoria en matrices grandes, donde el ahorro de memoria realmente importa. También se pueden usar en lugar de int, donde sus límites ayudan a aclarar su código; El hecho de que el rango de una variable sea limitado puede servir como una forma de documentación.

¿Qué significa esto? Algunas cosas: Primero y más importante, significa que estamos trabajando con 8 bits . Entonces, por ejemplo, podemos escribir el número 2 como 0000 0010. Sin embargo, dado que es el complemento de dos, escribimos un 2 negativo como este: 1111 1110. Lo que también significa es que convertir a hexadecimal es muy sencillo. Es decir, simplemente convierte cada segmento de 4 bits directamente en hexadecimal. Tenga en cuenta que para dar sentido a los números negativos en este esquema, primero deberá comprender el complemento de dos. Si aún no comprende el complemento a dos, puede leer una excelente explicación aquí: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


Convertir el complemento de dos a hexadecimal en general

Una vez que un número está en el complemento de dos, es muy simple convertirlo a hexadecimal. En general, la conversión de binario a hexadecimal es muy sencilla y, como verá en los siguientes dos ejemplos, puede pasar directamente del complemento de dos a hexadecimal.

Ejemplos

Ejemplo 1: Convierte 2 a Hex.

1) Primero convierta 2 a binario en el complemento a dos:

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

2) Ahora convierta binario a hexadecimal:

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

therefore 2 = 0000 0010 = 0x02. 

Ejemplo 2: Convertir -2 (en complemento de dos) a Hex.

1) Primero convierta -2 a binario en el complemento a dos:

-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) Ahora Convierte a Hex:

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

therefore: -2 = 1111 1110 = 0xFE.


Haciendo esto en Java

Ahora que hemos cubierto el concepto, descubrirá que podemos lograr lo que queremos con un simple enmascaramiento y cambio. La clave para entender es que el byte que está intentando convertir ya está en el complemento de dos. No haces esta conversión tú mismo. Creo que este es un importante punto de confusión sobre este tema. Tomemos, por ejemplo, la siguiente matriz de bytes:

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

Los convertimos manualmente a hexadecimal, arriba, pero ¿cómo podemos hacerlo en Java? Así es cómo:

Paso 1: Crea un StringBuffer para mantener nuestro cálculo.

StringBuffer buffer = new StringBuffer();

Paso 2: aísle los bits de orden superior, conviértalos a hexadecimal y agréguelos al búfer

Dado el número binario 1111 1110, podemos aislar los bits de orden superior desplazándolos primero por 4 y luego poniendo a cero el resto del número. Lógicamente, esto es simple, sin embargo, los detalles de implementación en Java (y en muchos idiomas) introducen una arruga debido a la extensión del signo. Esencialmente, cuando cambia un valor de byte, Java primero convierte su valor a un número entero y luego realiza la extensión de signo. Entonces, si bien esperaría que 1111 1110 >> 4 sea 0000 1111, en realidad, en Java se representa como el complemento de dos 0xFFFFFFFF.

Volviendo a nuestro ejemplo:

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

Entonces podemos aislar los bits con una máscara:

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

En Java podemos hacer todo esto de una vez:

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

La función forDigit solo asigna el número que le pasa al conjunto de números hexadecimales 0-F.

Paso 3: A continuación, necesitamos aislar los bits de orden inferior. Como los bits que queremos ya están en la posición correcta, podemos enmascararlos:

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

Como antes, en Java podemos hacer todo esto de una vez:

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

Al unir todo esto, podemos hacerlo como un bucle for y convertir toda la matriz:

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

Esperemos que esta explicación aclare las cosas para aquellos de ustedes que se preguntan exactamente qué está sucediendo en los muchos ejemplos que encontrarán en Internet. ¡Espero no haber cometido ningún error atroz, pero las sugerencias y correcciones son bienvenidas!

jsinglet
fuente
44
¡la mejor respuesta! La implementación simétrica de una cadena hexadecimal a byte convertiría y luego usaría Character.digit(), como(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn
21

La forma más rápida que he encontrado para hacer esto es la siguiente:

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

Es ~ 50 veces más rápido que String.format. si quieres probarlo:

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
        }

    }
}

Editar : Acabo de encontrar algo un poco más rápido y que se mantiene en una línea, pero no es compatible con JRE 9. Úselo bajo su propio riesgo

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);
Cristal
fuente
2
DatatypeConverter ya no está disponible en Java 9. Lo peligroso es que el código que lo usa se compilará en Java 1.8 o anterior (Java 9 con configuraciones de fuente anteriores), pero obtendrá una excepción de tiempo de ejecución en Java 9.
Stephen M -on strike-
Segundo punto de @StephenMs: usar esto con jre9 se bloqueará con la excepción ClassNotFound
Patrick Favre el
En realidad, simplemente puede extraer el método printHexBinary del código fuente de src.zip de jdk, que parece 1 veces más rápido que el primer método.
Fruta
1
Si trabaja con char array para HEXES constante, en lugar de String y charAt (), obtendrá ~ 20% más velocidad.
Dyorgio
15

Intenta de esta manera:

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

Tratando con la matriz (si te entendí correctamente):

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

Como se mencionó a los poligenelubricantes, String.format()es la respuesta correcta en comparación con Integer.toHexString()(ya que trata con los números negativos de la manera correcta).

0x2D9A3
fuente
2
Esto firmará extender, por ejemplo, intente -1.
Polygenelubricants
byte bv = 10; Cadena hexString = Integer.toHexString (bv); Esto parece funcionar de manera firme. Puedo aplicarlo individualmente en cada elemento de la matriz. El otro código (tratar con la matriz) devuelve un valor demasiado grande. ¿Cuál podría ser la razón para eso?
Vivek
@Vivek, eso es porque en caso de bvque devuelva un solo carácter hexadecimal . Mientras que el resto del código devuelve una cadena de caracteres hexadecimales . He cambiado el código con el delímetro para que pueda entenderlo ahora.
0x2D9A3
@Bar: todavía se puede usar Integer.toHexStringsi enmascarar el bytecon 0xFFde extensión de signo de deshacer.
Polygenelubricants
CAse 1 (Byte recibido: 68 salida hexadecimal: 44) Caso: 2 (byte recibido: -46 salida hexadecimal:: ffffffd2) Estoy obteniendo valores de salida inesperados en caso de conjuntos de bytes negativos ... ¿Cómo manejar esto?
Vivek
13

La mejor solución es este rudo one-liner:

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

como se menciona aquí

lince
fuente
44
DatatypeConverter ya no está disponible en Java 9. Lo peligroso es que el código que lo usa se compilará en Java 1.8 o anterior (Java 9 con configuraciones de fuente anteriores), pero obtendrá una excepción de tiempo de ejecución en Java 9.
Stephen M -on strike-
Triste cuando dices que no está en jdk9. new BigInteger(byteArray).toString(16)es el camino a seguir entonces. ¿Son problemas de rendimiento con eso?
prayagupd
Tal vez no sean problemas de rendimiento, pero se perderán los ceros iniciales (ya que no tienen sentido para un número como BigInteger)
Friso
Parece que todavía está en los documentos de Java 9 , por lo que parece que está bien usarlo por lo que puedo decir
Brad Parks,
Creo que, como se explica aquí , todavía está bien usarlo para java9, pero se eliminará en futuras versiones de java. también podrá usarlo con el 'nuevo' módulo independiente jaxb a partir de la versión 2.3.0 .
Lynx
11

Si desea una representación hexadecimal de ancho constante, es decir, en 0Alugar de A, para que pueda recuperar los bytes sin ambigüedades, intente format():

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

Una forma corta y simple de convertir byte[]a una cadena hexadecimal usando 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

¿Cómo funciona?

La clase de java.math.BigIntegerclase del sistema integrada ( java.math.BigInteger ) es compatible con datos binarios y hexadecimales:

  • Tiene un constructor BigInteger(signum=1, byte[])para crear un número entero grande byte[](establezca su primer parámetro signum= 1para manejar correctamente los bytes negativos)
  • Se usa BigInteger.toString(16)para convertir el entero grande en una cadena hexadecimal
  • Para analizar un número hexadecimal use new BigInteger("ffa74b", 16)- no maneja correctamente el cero inicial

Si desea tener el cero inicial en el resultado hexadecimal, verifique su tamaño y agregue el cero faltante si es necesario:

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

Notas

Use new BigInteger(1, bytes), en lugar de new BigInteger(bytes), porque Java está " roto por diseño " y el bytetipo de datos no contiene bytes, sino enteros pequeños con signo [-128 ... 127]. Si el primer byte es negativo, se BigIntegersupone que pasa un entero grande negativo. Simplemente pase 1como primer parámetro ( signum=1).

La conversión de nuevo de hexadecimal abyte[] es complicada: a veces un cero inicial ingresa en la salida producida y debe limpiarse así:

byte[] bytes = new BigInteger("ffa74b", 16).toByteArray();
if (bytes[0] == 0) {
    byte[] newBytes = new byte[bytes.length - 1];
    System.arraycopy(bytes, 1, newBytes, 0, newBytes.length);
    bytes = newBytes;
}

La última nota es si byte[]tiene varios ceros a la izquierda, se perderán.

Svetlin Nakov
fuente
1
Si el byte inicial tiene un valor decimal inferior a 16, también obtendrá una cadena con un número impar de caracteres hexadecimales.
Alex Jorgenson el
8

Si está contento de usar una biblioteca externa, la org.apache.commons.codec.binary.Hexclase tiene un encodeHexmétodo que toma byte[]ay devuelve a char[]. Este método es MUCHO más rápido que la opción de formato y encapsula los detalles de la conversión. También viene con un decodeHexmétodo para la conversión opuesta.

ajrskelton
fuente
44
Una forma aún más fácil es usar las funciones integradas javax.xml.bind.DatatypeConverter / parseHexBinary e printHexBinary. Ver stackoverflow.com/questions/9655181/…
Alan Thompson
2
+1 a esta opción. El Hex también tiene un método encodeHexString, que toma un byte [] y devuelve una cadena.
Mingjiang Shi
No olvide que el javaxespacio de nombres no siempre está disponible.
Mene
7

Puede usar el método de la biblioteca de Bouncy Castle Provider :

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

El paquete Crypto de Bouncy Castle es una implementación Java de algoritmos criptográficos. Este jar contiene el proveedor de JCE y la API ligera para las API de criptografía de Bouncy Castle para JDK 1.5 a JDK 1.8.

Dependencia de Maven:

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

o del códec de Apache Commons :

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

El paquete Apache Commons Codec contiene codificadores y decodificadores simples para varios formatos, como Base64 y Hexadecimal. Además de estos codificadores y decodificadores ampliamente utilizados, el paquete de códec también mantiene una colección de utilidades de codificación fonética.

Dependencia de Maven:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>
Tal como
fuente
Sí, esta es la mejor solución , pero requiere una biblioteca externa: 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 el
5

Este es el código que he encontrado para ejecutar el más rápido hasta ahora. Lo ejecuté en matrices de bytes 109015 de longitud 32, en 23 ms. Lo estaba ejecutando en una máquina virtual, por lo que probablemente se ejecutará más rápido en metal desnudo.

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

Entonces solo puedes hacer

String s = new String( encodeHex(myByteArray) );
Jerinaw
fuente
3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));
Wender
fuente
No funciona: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)regresa"-fdfcfbfb"
Martin Vysny
Es un resultado correcto. Estás trabajando con los bytes '-1', '2' ... '5'. Esos bytes no tienen visualización ( unicode.org ) si su intención es trabajar con el literal '-1', '2' ... '5', debe trabajar con los valores de cadena.
Wender
Es un resultado incorrecto. El valor de byte de Java de -1 es de hecho 0xFF (es el mismo que (int) 255) ya que los bytes de Java están firmados, por lo que el resultado debería ser FF02030405. Si prueba la solución @Jerinaw anterior, verá que imprimirá la salida correcta. Ver también la solución de Svetlin Nakov a continuación.
Martin Vysny
2

Aquí hay una función simple para convertir byte a hexadecimal

   private static String convertToHex(byte[] data) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) {
        int halfbyte = (data[i] >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));
            halfbyte = data[i] & 0x0F;
        } while(two_halfs++ < 1);
    }
    return buf.toString();
}
AzizSM
fuente
2

Otros han cubierto el caso general. Pero si tiene una matriz de bytes de una forma conocida, por ejemplo, una dirección MAC, entonces puede:

byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };

String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
                           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 
jww
fuente
1

Crear (y destruir) un montón de Stringinstancias no es una buena manera si el rendimiento es un problema.

Ignore esos argumentos verbales (duplicados) que verifican las declaraciones if. Eso es para (otro) propósito educativo.

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

Codificación ...

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

Descodificación...

/**
 * Decodes a single nibble.
 *
 * @param encoded the nibble to decode.
 *
 * @return the decoded half octet.
 */
protected static int decodeHalf(final int encoded) {

    switch (encoded) {
        case 0x30: // '0'
        case 0x31: // '1'
        case 0x32: // '2'
        case 0x33: // '3'
        case 0x34: // '4'
        case 0x35: // '5'
        case 0x36: // '6'
        case 0x37: // '7'
        case 0x38: // '8'
        case 0x39: // '9'
            return encoded - 0x30;
        case 0x41: // 'A'
        case 0x42: // 'B'
        case 0x43: // 'C'
        case 0x44: // 'D'
        case 0x45: // 'E'
        case 0x46: // 'F'
            return encoded - 0x37;
        case 0x61: // 'a'
        case 0x62: // 'b'
        case 0x63: // 'c'
        case 0x64: // 'd'
        case 0x65: // 'e'
        case 0x66: // 'f'
            return encoded - 0x57;
        default:
            throw new IllegalArgumentException("illegal half: " + encoded);
    }
}


/**
 * Decodes two nibbles into a single octet.
 *
 * @param encoded the nibble array.
 * @param offset the offset in the array.
 *
 * @return decoded octet.
 */
protected static int decodeSingle(final byte[] encoded, final int offset) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if (encoded.length < 2) {
        // not required
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") < 2");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("offset(" + offset + ") < 0");
    }

    if (offset >= encoded.length - 1) {
        throw new IllegalArgumentException(
            "offset(" + offset + ") >= encoded.length(" + encoded.length
            + ") - 1");
    }

    return (decodeHalf(encoded[offset]) << 4)
           | decodeHalf(encoded[offset + 1]);
}


/**
 * Encodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the encoded octets.
 */
protected static byte[] decodeMultiple(final byte[] encoded) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if ((encoded.length & 0x01) == 0x01) {
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") is not even");
    }

    final byte[] decoded = new byte[encoded.length >> 1];

    int offset = 0;
    for (int i = 0; i < decoded.length; i++) {
        decoded[i] = (byte) decodeSingle(encoded, offset);
        offset += 2;
    }

    return decoded;
}


/**
 * Decodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the decoded octets.
 */
public byte[] decode(final byte[] encoded) {

    return decodeMultiple(encoded);
}
Jin Kwon
fuente
1

Esta es una manera muy rápida. No se necesitan bibliotecas externas.

final protected static char[] HEXARRAY = "0123456789abcdef".toCharArray();

    public static String encodeHexString( byte[] bytes ) {

        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEXARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEXARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }
bapho
fuente
1

No pude entender exactamente qué querías decir con byte String, pero aquí hay algunas conversiones de byte a String y viceversa, por supuesto, hay mucho más en las documentaciones oficiales.

Integer intValue = 149;

El valor del byte correspondiente es:

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

recuperar el valor entero de una variable Byte:

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

Desde Byte e Integer hasta la cadena hexadecimal:
esta es la forma en que lo hago:

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

Conversión de una matriz de bytes en una cadena hexadecimal: por
lo que sé, no existe una función simple para convertir todos los elementos dentro de una matriz de algunos Objecten elementos de otro Object, por lo que debe hacerlo usted mismo. Puede usar las siguientes funciones:

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

Y de la cadena hexadecimal al 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;
}  

Es demasiado tarde pero espero que esto pueda ayudar a otros;)

Mehdi
fuente
1

Ahí está tu método rápido:

    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];
    }
lazo
fuente
1
feo, pero probablemente muy eficiente. :-)
Rich S
1

Al igual que algunas otras respuestas, recomiendo usar String.format()y BigInteger. Pero para interpretar la matriz de bytes como una representación binaria big-endian en lugar de una representación binaria del complemento a dos (con signum y uso incompleto del posible rango de valores hexadecimales) use BigInteger (int signum, byte [] magnitud) , no BigInteger (byte [] val ) .

Por ejemplo, para una matriz de bytes de longitud 8 use:

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

Ventajas:

  • ceros a la izquierda
  • sin señal
  • solo funciones incorporadas
  • solo una línea de código

Desventaja:

  • puede haber formas más eficientes de hacerlo

Ejemplo:

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

Salida de ejemplo:

big-endian       | two's-complement
-----------------|-----------------
3971B56BC7C80590 | 3971B56BC7C80590
64D3C133C86CCBDC | 64D3C133C86CCBDC
B232EFD5BC40FA61 | -4DCD102A43BF059F
CD350CC7DF7C9731 | -32CAF338208368CF
82CDC9ECC1BC8EED | -7D3236133E437113
F438C8C34911A7F5 | -BC7373CB6EE580B
5E99738BE6ACE798 | 5E99738BE6ACE798
A565FE5CE43AA8DD | -5A9A01A31BC55723
032EBA783D2E9A9F | 032EBA783D2E9A9F
8FDAA07263217ABA | -70255F8D9CDE8546
Jan Martin Keil
fuente
-2

Utilizar

Integer.toHexString((int)b);
Juriy
fuente
¡No hay ceros iniciales adicionales!
user1722245