¿Cómo inicializo una matriz de bytes en Java?

138

Tengo que almacenar algunos valores constantes (UUID) en forma de matriz de bytes en Java, y me pregunto cuál sería la mejor manera de inicializar esas matrices estáticas. Así es como lo estoy haciendo actualmente, pero siento que debe haber una mejor manera.

private static final byte[] CDRIVES = new byte[] { (byte)0xe0, 0x4f, (byte)0xd0,
    0x20, (byte)0xea, 0x3a, 0x69, 0x10, (byte)0xa2, (byte)0xd8, 0x08, 0x00, 0x2b,
    0x30, 0x30, (byte)0x9d };
private static final byte[] CMYDOCS = new byte[] { (byte)0xba, (byte)0x8a, 0x0d,
    0x45, 0x25, (byte)0xad, (byte)0xd0, 0x11, (byte)0x98, (byte)0xa8, 0x08, 0x00,
    0x36, 0x1b, 0x11, 0x03 };
private static final byte[] IEFRAME = new byte[] { (byte)0x80, 0x53, 0x1c,
    (byte)0x87, (byte)0xa0, 0x42, 0x69, 0x10, (byte)0xa2, (byte)0xea, 0x08,
    0x00, 0x2b, 0x30, 0x30, (byte)0x9d };
...
and so on

¿Hay algo que pueda usar que pueda ser menos eficiente, pero que se vea más limpio? por ejemplo:

private static final byte[] CDRIVES =
    new byte[] { "0xe04fd020ea3a6910a2d808002b30309d" };
dfickling
fuente

Respuestas:

111

Usando una función que convierte una cadena hexa a byte[], podría hacer

byte[] CDRIVES = hexStringToByteArray("e04fd020ea3a6910a2d808002b30309d");

¿Te sugiero que uses la función definida por Dave L en Convertir una representación de cadena de un volcado hexadecimal en una matriz de bytes usando Java?

Lo inserto aquí para una máxima legibilidad:

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

Si deja CDRIVES staticy final, la caída del rendimiento es irrelevante.

Denys Séguret
fuente
78
byte[] myvar = "Any String you want".getBytes();

Los literales de cadena se pueden escapar para proporcionar cualquier carácter:

byte[] CDRIVES = "\u00e0\u004f\u00d0\u0020\u00ea\u003a\u0069\u0010\u00a2\u00d8\u0008\u0000\u002b\u0030\u0030\u009d".getBytes();
petmez
fuente
50
¿Eso no convierte la cadena "0000"a {0x30,0x30,0x30,0x30}(ASCII) en lugar de {0x00,0x00,0x00,0x00}(binario) como lo desea el póster?
jww
55
Mira el título de la pregunta. Luego mire hacia atrás a esta respuesta. Ahora dime, ¿qué tiene de malo? Puede que no resuelva el problema particular del cartel, pero seguro que resolvió el mío. Necesitaba transformar una cadena en una matriz de bytes para usarla como semilla para un generador de números pseudoaleatorios y esto funcionó de maravilla.
e18r
@ e18r Está generando bytes, sí, pero no sabe cuál, ya que esto depende del juego de caracteres predeterminado. Al menos use .getBytes (codificación deseada).
cuant
@petmez pregunta tonta: en JAVA, es algo así como "" .getBytes (UTF_8)); (getBytes en una cadena vacía) algo seguro que hacer? ¿Es 'legal'? O simplemente puedo hacer: = nuevo byte [0]; ?
Robert Achmann
1
@RobertAchmann "" .getbytes ("UTF-8") debería devolver una matriz vacía y es perfectamente legal.
Jazzepi
33

En Java 6, hay un método que hace exactamente lo que quieres:

private static final byte[] CDRIVES = javax.xml.bind.DatatypeConverter.parseHexBinary("e04fd020ea3a6910a2d808002b30309d")

Alternativamente, podría usar Google Guava :

import com.google.common.io.BaseEncoding;
private static final byte[] CDRIVES = BaseEncoding.base16().lowerCase().decode("E04FD020ea3a6910a2d808002b30309d".toLowerCase());

El método de la guayaba es exagerado, cuando está utilizando matrices pequeñas. Pero Guava también tiene versiones que pueden analizar flujos de entrada. Esta es una buena característica cuando se trata de grandes entradas hexadecimales.

stefan.schwetschke
fuente
El ejemplo de Guava no funciona tal como está escrito: debe serlo base16().lowerCase().decode(...)si tiene dígitos hexadecimales en minúsculas. docs.guava-libraries.googlecode.com/git/javadoc/com/google/…
Peter DeGlopper
@PeterDeGlopper Buen hallazgo, he actualizado la respuesta para que el código ahora maneje cadenas con caracteres en mayúscula y minúscula.
stefan.schwetschke
1
javax.xml.bindfue eliminado tristemente en Java 9.
randomdude999
7

Puede usar la clase UUID de Java para almacenar estos valores, en lugar de las matrices de bytes:

UUID

public UUID(long mostSigBits,
            long leastSigBits)

Construye un nuevo UUID utilizando los datos especificados. mostSigBits se utiliza para los 64 bits más significativos del UUID y leastSigBits se convierte en los 64 bits menos significativos del UUID.

Jon
fuente
2

En lo que respecta a un proceso limpio, puede usar el objeto ByteArrayOutputStream ...

ByteArrayOutputStream bObj = new ByteArrayOutputStream();
bObj.reset();

// escribe todos los valores en bObj uno por uno usando

bObj.write(byte value)

// cuando termines puedes obtener el byte [] usando

CDRIVES = bObj.toByteArray();

// de lo que puedes repetir el proceso similar para CMYDOCS e IEFRAME también,

NOTA Esta no es una solución eficiente si realmente tiene una matriz pequeña.

Amit
fuente
2

Una solución sin bibliotecas, longitud dinámica devuelta, interpretación entera sin signo (no complemento de dos)

    public static byte[] numToBytes(int num){
    if(num == 0){
        return new byte[]{};
    }else if(num < 256){
        return new byte[]{ (byte)(num) };
    }else if(num < 65536){
        return new byte[]{ (byte)(num >>> 8),(byte)num };
    }else if(num < 16777216){
        return new byte[]{ (byte)(num >>> 16),(byte)(num >>> 8),(byte)num };
    }else{ // up to 2,147,483,647
        return new byte[]{ (byte)(num >>> 24),(byte)(num >>> 16),(byte)(num >>> 8),(byte)num };
    }
}
ZMitton
fuente
1

Mi opción preferida en esta circunstancia es usar org.apache.commons.codec.binary.Hexlas API útiles para convertir entre Stringhexadecimal y binario. Por ejemplo:

  1. Hex.decodeHex(char[] data)que arroja un DecoderExceptionsi hay caracteres no hexadecimales en la matriz, o si hay un número impar de caracteres.

  2. Hex.encodeHex(byte[] data)es la contraparte del método de decodificación anterior y escupe el char[].

  3. Hex.encodeHexString(byte[] data)que convierte de nuevo de una bytematriz a a String.

Uso: Hex.decodeHex("dd645a2564cbe648c8336d2be5eafaa6".toCharArray())

rbrtl
fuente
1

Puede usar esta función de utilidad:

public static byte[] fromHexString(String src) {
    byte[] biBytes = new BigInteger("10" + src.replaceAll("\\s", ""), 16).toByteArray();
    return Arrays.copyOfRange(biBytes, 1, biBytes.length);
}

A diferencia de las variantes de Denys Séguret y stefan.schwetschke, permite insertar símbolos de separación (espacios, tabulaciones, etc.) en la cadena de entrada, lo que lo hace más legible.

Ejemplo de uso:

private static final byte[] CDRIVES
    = fromHexString("e0 4f d0 20 ea 3a 69 10 a2 d8 08 00 2b 30 30 9d");
private static final byte[] CMYDOCS
    = fromHexString("BA8A0D4525ADD01198A80800361B1103");
private static final byte[] IEFRAME
    = fromHexString("80531c87 a0426910 a2ea0800 2b30309d");
John McClane
fuente
1

El tipo interno más pequeño, que en tiempo de compilación puede asignarse por números hexadecimales es char , como

private static final char[] CDRIVES_char = new char[] {0xe0, 0xf4, ...};

Para tener una matriz de bytes equivalente, uno podría implementar conversiones como

public static byte[] charToByteArray(char[] x)
{
    final byte[] res = new byte[x.length];
    for (int i = 0; i < x.length; i++)
    {
        res[i] = (byte) x[i];
    }
    return res;
}

public static byte[][] charToByteArray(char[][] x)
{
    final byte[][] res = new byte[x.length][];
    for (int i = 0; i < x.length; i++)
    {
        res[i] = charToByteArray(x[i]);
    }
    return res;
}
Sam Ginrich
fuente
-2
private static final int[] CDRIVES = new int[] {0xe0, 0xf4, ...};

y después del acceso convertir a byte.

Frankie
fuente