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.
@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)=00000010(base 2)
2) Ahora convierta binario a hexadecimal:
0000=0x0 in hex
0010=0x2 in hex
therefore 2=00000010=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)=00000010(direct conversion to binary)11111101(invert bits)11111110(add 1)
therefore:-2=11111110(in two's complement)
2) Ahora Convierte a Hex:
1111=0xF in hex
1110=0xE in hex
therefore:-2=11111110=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 =newbyte[]{-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 =newStringBuffer();
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:
11111110>>4(shift right 4)=11111111111111111111111111111111(32 bit sign-extended number in two's complement)
Entonces podemos aislar los bits con una máscara:
11111111111111111111111111111111&0xF=00000000000000000000000000001111
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:
11111110&0xF=00000000000000000000000000001110(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!
¡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:
Es ~ 50 veces más rápido que String.format. si quieres probarlo:
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}}}
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
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.
Tratando con la matriz (si te entendí correctamente):
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 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).
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?
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 =newStringBuilder();for(byte bb : byteArray){
result.append(String.format("%02X", bb));}return result.toString();
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í:
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.
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.
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.
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.
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.
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;}
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
/**
* 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);}
Descodificación...
/**
* 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);}
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 =149Byte aByte = anInt.byteValue();String hexFromInt ="".format("0x%x", anInt);// This will output 0x95String 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:
publicstaticString 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 []:
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;}
Es demasiado tarde pero espero que esto pueda ayudar a otros;)
Por ejemplo, para una matriz de bytes de longitud 8 use:
String.format("%016X",newBigInteger(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 =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();}
Respuestas:
Ver también
java.util.Formatter
sintaxis%[flags][width]conversion
'0'
: el resultado se rellenará con ceros2
'X'
: el resultado se formatea como un entero hexadecimal, mayúsculaMirando el texto de la pregunta, también es posible que esto sea lo que se solicita:
Varias respuestas aquí utiliza
Integer.toHexString(int)
; Esto es factible, pero con algunas advertencias. Como el parámetro es anint
, se realiza una conversión primitiva de ampliación albyte
argumento, que implica la extensión del signo.El 8 bits
byte
, que está firmado en Java, está extendido a 32 bitsint
. Para deshacer efectivamente esta extensión de signo, se puede enmascararbyte
con0xFF
.Otro problema con el uso
toHexString
es que no rellena con ceros:Ambos factores combinados deberían hacer que la
String.format
solución sea más preferible.Referencias
byte
, desde-128
hasta127
, inclusivefuente
toHexString
. Tienes que enmascararlo& 0xFF
,Integer.toHexString(-46 & 0xFF)
es decir, es"d2"
.byte
valor& 0xFF
cada vez. laformat
solución anterior también puede requerir enmascarar dependiendo de lo que realmente esté usando como argumento.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:
¿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) Ahora convierta binario a hexadecimal:
Ejemplo 2: Convertir -2 (en complemento de dos) a Hex.
1) Primero convierta -2 a binario en el complemento a dos:
2) Ahora Convierte a Hex:
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:
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.
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:
Entonces podemos aislar los bits con una máscara:
En Java podemos hacer todo esto de una vez:
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:
Como antes, en Java podemos hacer todo esto de una vez:
Al unir todo esto, podemos hacerlo como un bucle for y convertir toda la matriz:
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!
fuente
Character.digit()
, como(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
La forma más rápida que he encontrado para hacer esto es la siguiente:
Es ~ 50 veces más rápido que
String.format
. si quieres probarlo: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
fuente
printHexBinary
del código fuente de src.zip de jdk, que parece 1 veces más rápido que el primer método.Intenta de esta manera:
Tratando con la matriz (si te entendí correctamente):
Como se mencionó a los poligenelubricantes,
String.format()
es la respuesta correcta en comparación conInteger.toHexString()
(ya que trata con los números negativos de la manera correcta).fuente
-1
.bv
que 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.Integer.toHexString
si enmascarar elbyte
con0xFF
de extensión de signo de deshacer.La mejor solución es este rudo one-liner:
como se menciona aquí
fuente
new BigInteger(byteArray).toString(16)
es el camino a seguir entonces. ¿Son problemas de rendimiento con eso?Si desea una representación hexadecimal de ancho constante, es decir, en
0A
lugar deA
, para que pueda recuperar los bytes sin ambigüedades, intenteformat()
:fuente
Una forma corta y simple de convertir
byte[]
a una cadena hexadecimal usandoBigInteger
:¿Cómo funciona?
La clase de
java.math.BigInteger
clase del sistema integrada ( java.math.BigInteger ) es compatible con datos binarios y hexadecimales:BigInteger(signum=1, byte[])
para crear un número entero grandebyte[]
(establezca su primer parámetrosignum
=1
para manejar correctamente los bytes negativos)BigInteger.toString(16)
para convertir el entero grande en una cadena hexadecimalnew BigInteger("ffa74b", 16)
- no maneja correctamente el cero inicialSi desea tener el cero inicial en el resultado hexadecimal, verifique su tamaño y agregue el cero faltante si es necesario:
Notas
Use
new BigInteger(1, bytes)
, en lugar denew BigInteger(bytes)
, porque Java está " roto por diseño " y elbyte
tipo de datos no contiene bytes, sino enteros pequeños con signo [-128 ... 127]. Si el primer byte es negativo, seBigInteger
supone que pasa un entero grande negativo. Simplemente pase1
como primer parámetro (signum=1
).La conversión de nuevo de hexadecimal a
byte[]
es complicada: a veces un cero inicial ingresa en la salida producida y debe limpiarse así:La última nota es si
byte[]
tiene varios ceros a la izquierda, se perderán.fuente
Si está contento de usar una biblioteca externa, la
org.apache.commons.codec.binary.Hex
clase tiene unencodeHex
método que tomabyte[]
ay devuelve achar[]
. 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 undecodeHex
método para la conversión opuesta.fuente
javax
espacio de nombres no siempre está disponible.Puede usar el método de la biblioteca de Bouncy Castle Provider :
Dependencia de Maven:
o del códec de Apache Commons :
Dependencia de Maven:
fuente
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.
Entonces solo puedes hacer
fuente
fuente
BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)
regresa"-fdfcfbfb"
(int) 255
) ya que los bytes de Java están firmados, por lo que el resultado debería serFF02030405
. 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.Aquí hay una función simple para convertir byte a hexadecimal
fuente
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:
fuente
Crear (y destruir) un montón de
String
instancias 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 ...
Descodificación...
fuente
Esta es una manera muy rápida. No se necesitan bibliotecas externas.
fuente
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.
El valor del byte correspondiente es:
recuperar el valor entero de una variable Byte:
Desde Byte e Integer hasta la cadena hexadecimal:
esta es la forma en que lo hago:
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
Object
en elementos de otroObject
, por lo que debe hacerlo usted mismo. Puede usar las siguientes funciones:Del byte [] a String:
Y de la cadena hexadecimal al byte []:
Es demasiado tarde pero espero que esto pueda ayudar a otros;)
fuente
Ahí está tu método rápido:
fuente
Al igual que algunas otras respuestas, recomiendo usar
String.format()
yBigInteger
. 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:
Ventajas:
Desventaja:
Ejemplo:
Salida de ejemplo:
fuente
Utilizar
fuente