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.
@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)=00000010(base 2)
2) Agora converta binário em hexadecimal:
0000=0x0 in hex
0010=0x2 in hex
therefore 2=00000010=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)=00000010(direct conversion to binary)11111101(invert bits)11111110(add 1)
therefore:-2=11111110(in two's complement)
2) Agora converta para hex:
1111=0xF in hex
1110=0xE in hex
therefore:-2=11111110=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 =newbyte[]{-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 =newStringBuffer();
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:
11111110>>4(shift right 4)=11111111111111111111111111111111(32 bit sign-extended number in two's complement)
Podemos então isolar os bits com uma máscara:
11111111111111111111111111111111&0xF=00000000000000000000000000001111
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:
11111110&0xF=00000000000000000000000000001110(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!
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:
É ~ 50x mais rápido que String.format. se você quiser testá-lo:
publicclassMyTest{privatestaticfinalString HEXES ="0123456789ABCDEF";@Testpublicvoid 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++){finalStringBuilder hex =newStringBuilder(2* raw.length);for(finalbyte 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 =newStringBuilder(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
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.
byte[] bytes ={9,10,11,15,16};StringBuffer result =newStringBuffer();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).
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?
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 =newStringBuilder();for(byte bb : byteArray){
result.append(String.format("%02X", bb));}return result.toString();
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:
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.
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.
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.
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.
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.
publicstaticfinalchar[] HEX_DIGITS ={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};publicstaticchar[] encodeHex(finalbyte[] data ){finalint l = data.length;finalchar[] out =newchar[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;}
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
/**
* Encodes a single nibble.
*
* @param decoded the nibble to encode.
*
* @return the encoded half octet.
*/protectedstaticint encodeHalf(finalint decoded){switch(decoded){case0x00:case0x01:case0x02:case0x03:case0x04:case0x05:case0x06:case0x07:case0x08:case0x09:return decoded +0x30;// 0x30('0') - 0x39('9')case0x0A:case0x0B:case0x0C:case0x0D:case0x0E:case0x0F:return decoded +0x57;// 0x41('a') - 0x46('f')default:thrownewIllegalArgumentException("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.
*/protectedstaticvoid encodeSingle(finalint decoded,finalbyte[] encoded,finalint offset){if(encoded ==null){thrownewIllegalArgumentException("null encoded");}if(encoded.length <2){// not requiredthrownewIllegalArgumentException("encoded.length("+ encoded.length +") < 2");}if(offset <0){thrownewIllegalArgumentException("offset("+ offset +") < 0");}if(offset >= encoded.length -1){thrownewIllegalArgumentException("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.
*/protectedstaticbyte[] encodeMultiple(finalbyte[] decoded){if(decoded ==null){thrownewIllegalArgumentException("null decoded");}finalbyte[] encoded =newbyte[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.
*/publicbyte[] encode(finalbyte[] decoded){return encodeMultiple(decoded);}
Decodificando ...
/**
* Decodes a single nibble.
*
* @param encoded the nibble to decode.
*
* @return the decoded half octet.
*/protectedstaticint decodeHalf(finalint encoded){switch(encoded){case0x30:// '0'case0x31:// '1'case0x32:// '2'case0x33:// '3'case0x34:// '4'case0x35:// '5'case0x36:// '6'case0x37:// '7'case0x38:// '8'case0x39:// '9'return encoded -0x30;case0x41:// 'A'case0x42:// 'B'case0x43:// 'C'case0x44:// 'D'case0x45:// 'E'case0x46:// 'F'return encoded -0x37;case0x61:// 'a'case0x62:// 'b'case0x63:// 'c'case0x64:// 'd'case0x65:// 'e'case0x66:// 'f'return encoded -0x57;default:thrownewIllegalArgumentException("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.
*/protectedstaticint decodeSingle(finalbyte[] encoded,finalint offset){if(encoded ==null){thrownewIllegalArgumentException("null encoded");}if(encoded.length <2){// not requiredthrownewIllegalArgumentException("encoded.length("+ encoded.length +") < 2");}if(offset <0){thrownewIllegalArgumentException("offset("+ offset +") < 0");}if(offset >= encoded.length -1){thrownewIllegalArgumentException("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.
*/protectedstaticbyte[] decodeMultiple(finalbyte[] encoded){if(encoded ==null){thrownewIllegalArgumentException("null encoded");}if((encoded.length &0x01)==0x01){thrownewIllegalArgumentException("encoded.length("+ encoded.length +") is not even");}finalbyte[] decoded =newbyte[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.
*/publicbyte[] decode(finalbyte[] encoded){return decodeMultiple(encoded);}
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 =149Byte aByte = anInt.byteValue();String hexFromInt ="".format("0x%x", anInt);// This will output 0x95String 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:
publicstaticString 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 []:
publicstaticbyte[] hexStringToByteArray(String hexString){byte[] bytes =newbyte[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;)
Por exemplo, para uma matriz de bytes de comprimento 8, use:
String.format("%016X",newBigInteger(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 =newbyte[8];Random r =newRandom();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",newBigInteger(1,bytes)));System.out.print(" | ");System.out.print(String.format("%016X",newBigInteger(bytes)));System.out.println();}
Respostas:
Veja também
java.util.Formatter
sintaxe%[flags][width]conversion
'0'
- O resultado será preenchido com zero2
'X'
- o resultado é formatado como um número inteiro hexadecimal, maiúsculoObservando o texto da pergunta, também é possível que seja solicitado:
Várias respostas aqui usam
Integer.toHexString(int)
; isso é possível, mas com algumas ressalvas. Como o parâmetro é umint
, uma conversão primitiva de ampliação é executada nobyte
argumento, o que envolve a extensão do sinal.O de 8 bits
byte
, assinado em Java, é estendido para um sinal de 32 bitsint
. Para desfazer efetivamente essa extensão de sinal, é possível mascarar obyte
com0xFF
.Outro problema com o uso
toHexString
é que ele não é preenchido com zeros:Ambos os fatores combinados devem tornar a
String.format
solução mais preferível.Referências
byte
, de-128
até127
, inclusivefonte
toHexString
. Você tem que mascará-lo com& 0xFF
, ou seja,Integer.toHexString(-46 & 0xFF)
é"d2"
.byte
valor& 0xFF
sempre. aformat
solução acima também pode exigir mascaramento, dependendo do que você está usando como argumento.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 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) Agora converta binário em hexadecimal:
Exemplo 2: Converta -2 (no complemento de dois) para Hex.
1) Primeiro converta -2 para binário no complemento de dois:
2) Agora converta para hex:
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:
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.
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:
Podemos então isolar os bits com uma máscara:
Em Java, podemos fazer tudo isso de uma só vez:
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:
Como antes, em Java, podemos fazer isso de uma só vez:
Juntando tudo isso, podemos fazer isso como um loop for e converter toda a matriz:
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!
fonte
Character.digit()
, como(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
A maneira mais rápida que encontrei para fazer isso é a seguinte:
É ~ 50x mais rápido que
String.format
. se você quiser testá-lo: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
fonte
printHexBinary
do código-fonte do src.zip do jdk, que parece 1 vez mais rápido que o primeiro método.Tente desta maneira:
Lidando com array (se entendi corretamente):
Como os poligenelubrificantes mencionados,
String.format()
é a resposta certa em comparação comInteger.toHexString()
(uma vez que lida com números negativos da maneira correta).fonte
-1
.bv
disso, 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.Integer.toHexString
se mascarar obyte
com0xFF
para desfazer a extensão do sinal.A melhor solução é esse one-liner durão:
como mencionado aqui
fonte
new BigInteger(byteArray).toString(16)
é o caminho a seguir então. São problemas de perf com isso ??Se você deseja uma representação hexadecimal de largura constante, ou seja,
0A
vez deA
, para recuperar os bytes sem ambiguidade, tenteformat()
:fonte
Uma maneira curta e simples de converter
byte[]
em sequência hexadecimal usandoBigInteger
:Como funciona?
A classe de
java.math.BigInteger
classe do sistema interna ( java.math.BigInteger ) é compatível com dados binários e hexadecimais:BigInteger(signum=1, byte[])
para criar um grande número inteirobyte[]
(defina seu primeiro parâmetrosignum
=1
para manipular corretamente os bytes negativos)BigInteger.toString(16)
para converter o número inteiro grande em sequência hexadecimalnew BigInteger("ffa74b", 16)
- não lida corretamente com o zero inicialSe você quiser ter o zero inicial no resultado hexadecimal, verifique seu tamanho e adicione o zero ausente, se necessário:
Notas
Use
new BigInteger(1, bytes)
, em vez denew BigInteger(bytes)
, porque Java é " quebrado por design " e obyte
tipo de dados não contém bytes, mas assinou números inteiros minúsculos [-128 ... 127]. Se o primeiro byte for negativo,BigInteger
assume-se que você passa um número inteiro grande negativo. Apenas passe1
como primeiro parâmetro (signum=1
).A conversão de hex para hex
byte[]
é complicada: às vezes um zero inicial entra na saída produzida e deve ser limpo assim:A última nota é se o
byte[]
tiver vários zeros à esquerda, eles serão perdidos.fonte
Se você está feliz em usar uma biblioteca externa, a
org.apache.commons.codec.binary.Hex
classe possui umencodeHex
método que pegabyte[]
ae retorna achar[]
. Este método é MUITO mais rápido que a opção de formato e encapsula os detalhes da conversão. Também vem com umdecodeHex
método para a conversão oposta.fonte
javax
espaço para nome nem sempre está disponível.Você pode usar o método da biblioteca Bouncy Castle Provider :
Dependência do Maven:
ou do Apache Commons Codec :
Dependência do Maven:
fonte
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.
Então você pode simplesmente fazer
fonte
fonte
BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)
retorna"-fdfcfbfb"
(int) 255
) desde que os bytes Java são assinados, portanto o resultado deve serFF02030405
. 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.Aqui está uma função simples para converter bytes em hexadecimal
fonte
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á:
fonte
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...
Decodificando ...
fonte
Esta é uma maneira muito rápida. Nenhuma biblioteca externa necessária.
fonte
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
O valor do byte correspondente é:
recupere o valor inteiro de uma variável Byte:
De Byte e Inteiro a Hex String:
É assim que eu faço:
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
Object
em elementos de outraObject
, então você deve fazer isso sozinho. Você pode usar as seguintes funções:De byte [] a String:
E da cadeia hexadecimal ao byte []:
É tarde demais, mas espero que isso ajude outros;)
fonte
Aqui está o seu método rápido:
fonte
Assim como algumas outras respostas, eu recomendo usar
String.format()
eBigInteger
. 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:
Vantagens:
Desvantagem:
Exemplo:
Exemplo de saída:
fonte
Usar
fonte