Como inicializar uma matriz de bytes em Java?

138

Eu tenho que armazenar alguns valores constantes (UUIDs) na forma de matriz de bytes em java, e estou me perguntando qual seria a melhor maneira de inicializar essas matrizes estáticas. É assim que estou fazendo atualmente, mas sinto que deve haver uma maneira melhor.

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

Existe algo que eu possa usar que seja menos eficiente, mas que pareça mais limpo? por exemplo:

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

Respostas:

111

Usando uma função que converte uma cadeia hexa em byte[], você pode fazer

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

Eu sugiro que você use a função definida por Dave L em Converter uma representação de seqüência de caracteres de um hex dump em uma matriz de bytes usando Java?

Eu insiro-o aqui para máxima legibilidade:

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

Se você deixar CDRIVES statice final, a queda de desempenho é irrelevante.

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

Literais de string podem ser escapados para fornecer qualquer caractere:

byte[] CDRIVES = "\u00e0\u004f\u00d0\u0020\u00ea\u003a\u0069\u0010\u00a2\u00d8\u0008\u0000\u002b\u0030\u0030\u009d".getBytes();
petmez
fonte
50
Isso não transforma a string "0000"em {0x30,0x30,0x30,0x30}(ASCII), em vez de {0x00,0x00,0x00,0x00}(binária), conforme desejado pelo pôster?
JWW
5
Veja o título da pergunta. Então olhe para esta resposta. Agora me diga, o que há de errado nisso? Pode não resolver o problema específico do pôster, mas com certeza resolveu o meu. Eu precisava transformar uma string em uma matriz de bytes para usar como semente de um gerador de números pseudo-aleatórios e isso funcionou como um encanto.
e18r
@ e18r Ele está gerando bytes, sim, mas você não sabe quais, desde esta descrição no conjunto de caracteres padrão. Pelo menos use .getBytes (desejadoEncodificação).
quant
@ petmez pergunta idiota: em JAVA, é algo como "" .getBytes (UTF_8)); (getBytes em uma string vazia) uma coisa segura a se fazer? é 'legal'? Ou posso apenas fazer: = novo byte [0]; ?
Robert Achmann 01/03/19
1
@RobertAchmann "" .getbytes ("UTF-8") deve retornar uma matriz vazia e é perfeitamente legal.
Jazzepi
33

No Java 6, existe um método que faz exatamente o que você deseja:

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

Como alternativa, você pode usar o Google Guava :

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

O método Guava é um exagero, quando você usa matrizes pequenas. Mas o Guava também possui versões que podem analisar fluxos de entrada. Esse é um recurso interessante ao lidar com grandes entradas hexadecimais.

stefan.schwetschke
fonte
O exemplo do Guava não funciona exatamente como está escrito - é necessário base16().lowerCase().decode(...)que você tenha dígitos hexadecimais em letras minúsculas. docs.guava-libraries.googlecode.com/git/javadoc/com/google/…
Peter DeGlopper
@PeterDeGlopper Boa descoberta, atualizei a resposta para que o código agora lide com seqüências de caracteres com caracteres em maiúsculas e minúsculas.
stefan.schwetschke
1
javax.xml.bindfoi tristemente removido no Java 9.
randomdude999 15/01/19
7

Você pode usar a classe Java UUID para armazenar esses valores, em vez de matrizes de bytes:

UUID

public UUID(long mostSigBits,
            long leastSigBits)

Constrói um novo UUID usando os dados especificados. mostSigBits é usado para os 64 bits mais significativos do UUID e lessSigBits se torna os 64 bits menos significativos do UUID.

Jon
fonte
2

No que diz respeito a um processo limpo, você pode usar o objeto ByteArrayOutputStream ...

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

// escreve todos os valores no bObj um por um usando

bObj.write(byte value)

// quando terminar, você pode obter o byte [] usando

CDRIVES = bObj.toByteArray();

// do que você pode repetir o processo semelhante para CMYDOCS e IEFRAME também,

NOTA Esta não é uma solução eficiente se você realmente possui uma matriz pequena.

Amit
fonte
2

Uma solução sem bibliotecas, comprimento dinâmico retornado, interpretação de número inteiro não assinado (complemento não dois)

    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
fonte
1

Minha opção preferida nessa circunstância é usar org.apache.commons.codec.binary.HexAPIs úteis para converter entre Stringy hex e binário. Por exemplo:

  1. Hex.decodeHex(char[] data)que gera a DecoderExceptionse houver caracteres não hexadecimais na matriz ou se houver um número ímpar de caracteres.

  2. Hex.encodeHex(byte[] data)é a contraparte do método de decodificação acima e cospe o char[].

  3. Hex.encodeHexString(byte[] data)que converte de volta de uma bytematriz para a String.

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

rbrtl
fonte
1

Você pode usar esta função de utilitário:

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

Diferentemente das variantes do Denys Séguret e stefan.schwetschke, ele permite inserir símbolos separadores (espaços, tabulações etc.) na cadeia de entrada, tornando-a mais legível.

Exemplo 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
fonte
1

O menor tipo interno, que em tempo de compilação pode ser atribuído por números hexadecimais, é char , como

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

Para ter uma matriz de bytes equivalente, é possível implantar conversões 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
fonte
-2
private static final int[] CDRIVES = new int[] {0xe0, 0xf4, ...};

e após o acesso converter para byte.

Frankie
fonte