Código Java Para converter bytes em Hexadecimal

184

Eu tenho uma matriz de bytes. Eu quero que cada byte String dessa matriz seja convertida em seus valores hexadecimais correspondentes.

Existe alguma função em Java para converter uma matriz de bytes em hexadecimal?

Vivek
fonte
2
O que você chama byte-array em Java é chamado de seqüência de byte em outros idiomas (por exemplo docs.racket-lang.org/guide/bytestrings.html )
Patrick Favre

Respostas:

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 "

Veja também

  • java.util.Formatter sintaxe
    • %[flags][width]conversion
      • Sinalizador '0'- O resultado será preenchido com zero
      • Largura 2
      • Conversão 'X'- o resultado é formatado como um número inteiro hexadecimal, maiúsculo

Observando o texto da pergunta, também é possível que seja solicitado:

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

Várias respostas aqui usam Integer.toHexString(int); isso é possível, mas com algumas ressalvas. Como o parâmetro é um int, uma conversão primitiva de ampliação é executada no byteargumento, o que envolve a extensão do sinal.

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

O de 8 bits byte, assinado em Java, é estendido para um sinal de 32 bits int. Para desfazer efetivamente essa extensão de sinal, é possível mascarar o bytecom 0xFF.

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

Outro problema com o uso toHexStringé que ele não é preenchido com zeros:

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

Ambos os fatores combinados devem tornar a String.formatsolução mais preferível.

Referências

poligenelubricants
fonte
@Vivek: o que é "um valor enormemente grande"? Qual é a entrada e qual é a saída?
polygenelubricants
Deixe-me explicar novamente .. Eu tenho uma coleção de cadeias de bytes em uma matriz. Mas o que preciso fazer é analisar cada byte separadamente. Portanto, não quero trabalhar em toda a matriz, mas em uma sequência de bytes individual de cada vez, que é um componente dessa matriz. A confusão surgiu devido à palavra " matriz ". Agora no código abaixo "byte bv = 10; String hexString = Inteiro.toHexString (bv);" CAse 1 (Byte Recebido: 68 Saída Hex:: 44) Caso: 2 (Byte Recebido: -46 Saída Hex:: ffffffd2) ......... Por que estou obtendo um resultado tão inesperado para alguns valores?
Vivek
1
@ Livek: leia minha resposta sobre o uso toHexString. Você tem que mascará-lo com & 0xFF, ou seja, Integer.toHexString(-46 & 0xFF)é "d2".
polygenelubricants
@polygenelubricants: Muito obrigado .. Parece que finalmente o código está funcionando bem .. É seguro usar a função HexString agora? Ou, pode haver algumas brechas na abordagem?
Vivek
1
@Vivek: é "seguro", você só precisa ter cuidado e mascarar o bytevalor & 0xFFsempre. a formatsolução acima também pode exigir mascaramento, dependendo do que você está usando como argumento.
polygenelubricants
65

Estou postando porque nenhuma das respostas existentes explica por que as abordagens funcionam, o que acho realmente importante para esse problema. Em alguns casos, isso faz com que a solução proposta pareça desnecessariamente complicada e sutil. Para ilustrar, fornecerei uma abordagem bastante direta, mas fornecerei um pouco mais de detalhes para ajudar a ilustrar por que funciona.

Primeiro, o que estamos tentando fazer? Queremos converter um valor de byte (ou uma matriz de bytes) em uma string que represente um valor hexadecimal em ASCII. Portanto, o primeiro passo é descobrir exatamente o que é um byte em Java:

O tipo de dados byte é um número inteiro de complemento assinado de dois bits de 8 bits . Tem um valor mínimo de -128 e um valor máximo de 127 (inclusive). O tipo de dados de bytes pode ser útil para economizar memória em matrizes grandes, onde a economia de memória realmente importa. Eles também podem ser usados ​​no lugar de int, onde seus limites ajudam a esclarecer seu código; o fato de o alcance de uma variável ser limitado pode servir como uma forma de documentação.

O que isto significa? Algumas coisas: Primeiro e mais importante, significa que estamos trabalhando com 8 bits . Por exemplo, podemos escrever o número 2 como 0000 0010. No entanto, como é o complemento de dois, escrevemos um 2 negativo como este: 1111 1110. O que também significa é que a conversão para hex é muito simples. Ou seja, você simplesmente converte cada segmento de 4 bits diretamente em hexadecimal. Observe que, para entender os números negativos nesse esquema, primeiro você precisa entender o complemento de dois. Se você ainda não entende o complemento de dois, pode ler uma excelente explicação, aqui: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


Convertendo o complemento de dois em hexadecimal em geral

Quando um número está no complemento de dois, é simples convertê-lo em hexadecimal. Em geral, a conversão de binário em hexadecimal é muito direta e, como você verá nos próximos dois exemplos, é possível ir diretamente do complemento de dois para hexadecimal.

Exemplos

Exemplo 1: Converta 2 em Hex.

1) Primeiro converta 2 para binário no complemento de dois:

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

2) Agora converta binário em hexadecimal:

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

therefore 2 = 0000 0010 = 0x02. 

Exemplo 2: Converta -2 (no complemento de dois) para Hex.

1) Primeiro converta -2 para binário no complemento de dois:

-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) Agora converta para hex:

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

therefore: -2 = 1111 1110 = 0xFE.


Fazendo isso em Java

Agora que abordamos o conceito, você descobrirá que podemos alcançar o que queremos com algumas máscaras e mudanças simples. A principal coisa a entender é que o byte que você está tentando converter já está no complemento de dois. Você não faz essa conversão sozinho. Penso que este é um ponto importante de confusão sobre esta questão. Tomemos, por exemplo, a seguinte matriz de bytes:

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

Nós apenas os convertemos manualmente em hexadecimal, acima, mas como podemos fazer isso em Java? Aqui está como:

Etapa 1: Crie um StringBuffer para armazenar nossa computação.

StringBuffer buffer = new StringBuffer();

Etapa 2: isole os bits de ordem superior, converta-os em hexadecimal e adicione-os ao buffer

Dado o número binário 1111 1110, podemos isolar os bits de ordem superior deslocando-os primeiro por 4 e depois zerando o restante do número. Logicamente, isso é simples, no entanto, os detalhes da implementação em Java (e em muitas linguagens) introduzem uma ruga devido à extensão do sinal. Essencialmente, quando você altera um valor de byte, o Java primeiro converte seu valor em um número inteiro e depois executa a extensão do sinal. Portanto, enquanto você esperaria que 1111 1110 >> 4 fosse 0000 1111, na realidade, em Java, ele é representado como o complemento dos dois 0xFFFFFFFF!

Então, voltando ao nosso exemplo:

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

Podemos então isolar os bits com uma máscara:

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

Em Java, podemos fazer tudo isso de uma só vez:

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

A função forDigit apenas mapeia o número que você passa para o conjunto de números hexadecimais 0-F.

Etapa 3: Em seguida, precisamos isolar os bits de ordem inferior. Como os bits que queremos já estão na posição correta, podemos apenas mascará-los:

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

Como antes, em Java, podemos fazer isso de uma só vez:

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

Juntando tudo isso, podemos fazer isso como um loop for e converter toda a 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));
}

Esperamos que esta explicação torne as coisas mais claras para aqueles que se perguntam exatamente o que está acontecendo nos muitos exemplos que você encontrará na internet. Espero não ter cometido erros flagrantes, mas sugestões e correções são muito bem-vindas!

jsinglet
fonte
4
melhor resposta! A implementação simétrica de uma string hexadecimal para byte usaria a conversão Character.digit(), como(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn
21

A maneira mais rápida que encontrei para fazer isso é a seguinte:

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

É ~ 50x mais rápido que String.format. se você quiser testá-lo:

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
        }

    }
}

Edit : Acabei de encontrar algo apenas um lil mais rápido e que mantém uma linha, mas não é compatível com o JRE 9. Use por sua conta e risco

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);
Crystark
fonte
2
O DatatypeConverter não está mais disponível no Java 9. O mais perigoso é o código que ele compila no Java 1.8 ou anterior (Java 9 com configurações de origem anteriores), mas obtém uma exceção de tempo de execução no Java 9.
Stephen M -on strike-
Eu segundo @StephenMs apontar: usando isso com jre9 irá falhar com ClassNotFound Exceção
Patrick Favre
Na verdade, pode simplesmente extrair o método printHexBinary do código-fonte do src.zip do jdk, que parece 1 vez mais rápido que o primeiro método.
Fruit
1
Se você trabalha com a matriz char para a constante HEXES, em vez de String e charAt (), ganha ~ 20% mais velocidade.
Dyorgio
15

Tente desta maneira:

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

Lidando com array (se entendi corretamente):

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 os poligenelubrificantes mencionados, String.format()é a resposta certa em comparação com Integer.toHexString()(uma vez que lida com números negativos da maneira correta).

0x2D9A3
fonte
2
Isso significará extensão, por exemplo, tente -1.
polygenelubricants
byte bv = 10; String hexString = Integer.toHexString (bv); Isso parece funcionar muito bem. Eu posso aplicá-lo individualmente em todos os elementos da matriz. O outro código (Lidando com a matriz) devolve um valor muito grande. O que poderia explicar a razão disso?
Vivek
@Vivek, isso ocorre porque, em caso bvdisso, retorna um único caractere hexadecimal . Enquanto o restante do código retorna uma sequência de caracteres hexadecimais . Alterei o código com o delímetro para que você possa entender agora.
0x2D9A3
@ Bar: você ainda pode usar Integer.toHexStringse mascarar o bytecom 0xFFpara desfazer a extensão do sinal.
polygenelubricants
CAse 1 (Byte Recebido: 68 Saída Hex:: 44) Caso: 2 (Byte Recebido: -46 Saída Hex:: ffffffd2) Estou recebendo valores de saída inesperados em caso de matrizes de bytes negativas ... Como lidar com isso?
Vivek
13

A melhor solução é esse one-liner durão:

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

como mencionado aqui

lince
fonte
4
O DatatypeConverter não está mais disponível no Java 9. O mais perigoso é o código que ele compila no Java 1.8 ou anterior (Java 9 com configurações de origem anteriores), mas obtém uma exceção de tempo de execução no Java 9.
Stephen M -on strike-
Triste quando você diz que não está no jdk9. new BigInteger(byteArray).toString(16)é o caminho a seguir então. São problemas de perf com isso ??
prayagupd
Talvez não perf questões, mas vai perder zeros à esquerda (como eles são sem sentido para um número como BigInteger é)
Friso
Parece que ele ainda está nos java 9 docs , por isso parece que ele está ok para usá-lo ainda do que eu posso dizer
Brad Parks
Eu acho que, como explicado aqui , ainda está ok para o java9, mas será removido em versões futuras do java. você também poderá usá-lo com o 'novo' módulo jaxb independente a partir da versão 2.3.0 .
lince
11

Se você deseja uma representação hexadecimal de largura constante, ou seja, 0A vez de A, para recuperar os bytes sem ambiguidade, tente format():

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

Uma maneira curta e simples de converter byte[]em sequência 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

Como funciona?

A classe de java.math.BigIntegerclasse do sistema interna ( java.math.BigInteger ) é compatível com dados binários e hexadecimais:

  • Tem um construtor BigInteger(signum=1, byte[])para criar um grande número inteiro byte[](defina seu primeiro parâmetrosignum = 1para manipular corretamente os bytes negativos)
  • Use BigInteger.toString(16)para converter o número inteiro grande em sequência hexadecimal
  • Para analisar um número hexadecimal, use new BigInteger("ffa74b", 16) - não lida corretamente com o zero inicial

Se você quiser ter o zero inicial no resultado hexadecimal, verifique seu tamanho e adicione o zero ausente, se necessário:

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

Notas

Use new BigInteger(1, bytes), em vez de new BigInteger(bytes), porque Java é " quebrado por design " e o bytetipo de dados não contém bytes, mas assinou números inteiros minúsculos [-128 ... 127]. Se o primeiro byte for negativo, BigIntegerassume-se que você passa um número inteiro grande negativo. Apenas passe 1como primeiro parâmetro ( signum=1).

A conversão de hex para hexbyte[] é complicada: às vezes um zero inicial entra na saída produzida e deve ser limpo assim:

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

A última nota é se o byte[]tiver vários zeros à esquerda, eles serão perdidos.

Svetlin Nakov
fonte
1
Se o byte à esquerda tiver um valor decimal menor que 16, você também receberá uma string com um número ímpar de caracteres hexadecimais.
Alex Jorgenson
8

Se você está feliz em usar uma biblioteca externa, a org.apache.commons.codec.binary.Hexclasse possui um encodeHexmétodo que pega byte[]ae retorna a char[]. Este método é MUITO mais rápido que a opção de formato e encapsula os detalhes da conversão. Também vem com um decodeHexmétodo para a conversão oposta.

ajrskelton
fonte
4
Uma maneira ainda mais fácil é usar as funções internas javax.xml.bind.DatatypeConverter / parseHexBinary e printHexBinary. Veja stackoverflow.com/questions/9655181/…
Alan Thompson
2
+1 nesta opção. O Hex também possui um método encodeHexString, que pega um byte [] e retorna uma String.
Mingjiang Shi
não esqueça que o javaxespaço para nome nem sempre está disponível.
Mene 31/03
7

Você pode usar o método da biblioteca Bouncy Castle Provider :

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

O pacote Bouncy Castle Crypto é uma implementação Java de algoritmos criptográficos. Este jar contém o provedor JCE e a API leve para as APIs de criptografia de castelo insuflável para JDK 1.5 a JDK 1.8.

Dependência do Maven:

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

ou do Apache Commons Codec :

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

O pacote do Apache Commons Codec contém codificadores e decodificadores simples para vários formatos, como Base64 e Hexadecimal. Além desses codificadores e decodificadores amplamente utilizados, o pacote de codecs também mantém uma coleção de utilitários de codificação fonética.

Dependência do Maven:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>
Assim como
fonte
Sim, esta é a melhor solução , mas requer uma biblioteca externa: Apache Commons Codec ( mvnrepository.com/artifact/commons-codec/commons-codec/1.11 ) ou BouncyCastle Provider ( mvnrepository.com/artifact/org.bouncycastle/bcprov- jdk15on / 1.60 )
Svetlin Nakov
5

Este é o código que eu encontrei para executar o mais rápido até agora. Eu o executei em matrizes de 109015 bytes de comprimento 32, em 23ms. Eu estava executando-o em uma VM, por isso provavelmente será executado mais rapidamente em 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;
}

Então você pode simplesmente fazer

String s = new String( encodeHex(myByteArray) );
Jerinaw
fonte
3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));
Wender
fonte
Não funciona: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)retorna"-fdfcfbfb"
Martin Vysny
É um resultado certo. Você está trabalhando com os bytes '-1', '2' ... '5'. Os bytes não têm visualização ( unicode.org ), se você pretende trabalhar com os literais '-1', '2' ... '5', você deve trabalhar com os valores da string.
Wender
É resultado errado. O valor do byte Java -1 é de fato 0xFF (é o mesmo que (int) 255) desde que os bytes Java são assinados, portanto o resultado deve ser FF02030405. Se você experimentar a solução @Jerinaw acima, verá que ela imprimirá a saída correta. Veja também a solução de Svetlin Nakov abaixo.
Martin Vysny
2

Aqui está uma função simples para converter bytes em 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
fonte
2

Outros abordaram o caso geral. Mas se você tiver uma matriz de bytes de um formulário conhecido, por exemplo, um endereço MAC, poderá:

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

Criando (e destruindo) um monte de String instâncias não é uma boa maneira se o desempenho for um problema.

Por favor, ignore os argumentos detalhados (duplicados) que verificam as declarações if. Isso é para (outros) propósitos educacionais.

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

Codificação...

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

Decodificando ...

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

Esta é uma maneira muito rápida. Nenhuma biblioteca externa necessária.

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

Eu não conseguia entender exatamente o que você queria dizer com byte String, mas aqui estão algumas conversões de byte para String e vice-versa, é claro que há muito mais nas documentações oficiais

Integer intValue = 149;

O valor do byte correspondente é:

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

recupere o valor inteiro de uma variável Byte:

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

De Byte e Inteiro a Hex String:
É assim que eu faço:

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

Convertendo uma matriz de bytes em uma sequência hexadecimal:
Até onde eu sei, não existe uma função simples para converter todos os elementos dentro de uma matriz de alguns Objectem elementos de outra Object, então você deve fazer isso sozinho. Você pode usar as seguintes funções:

De 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 cadeia hexadecimal ao 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;
}  

É tarde demais, mas espero que isso ajude outros;)

Mehdi
fonte
1

Aqui está o seu 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];
    }
ciclo
fonte
1
feio, mas provavelmente muito eficiente. :-)
Rich S
1

Assim como algumas outras respostas, eu recomendo usar String.format()e BigInteger. Mas, para interpretar a matriz de bytes como representação binária big-endian em vez de representação binária de complemento de dois (com signum e uso incompleto do intervalo de valores hexadecimais possíveis), use BigInteger (int signum, byte [] magnitude) , não BigInteger (byte [] val ) .

Por exemplo, para uma matriz de bytes de comprimento 8, use:

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

Vantagens:

  • zeros à esquerda
  • sem sinal
  • somente funções internas
  • apenas uma linha de código

Desvantagem:

  • pode haver maneiras mais eficientes de fazer isso

Exemplo:

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

Exemplo de saída:

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

Usar

Integer.toHexString((int)b);
Juriy
fonte
não há zeroso à frente extra!
user1722245