2011-04-11 30 views

Respuesta

57

lo que necesita saber el orden de bits de los bytes.

Suponiendo (como @ WhiteFang34) que bytes es un byte[] de longitud 4, entonces ...

Big-endian:

int x = java.nio.ByteBuffer.wrap(bytes).getInt(); 

ascendente hacia la izquierda:

int x = java.nio.ByteBuffer.wrap(bytes).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt(); 
+1

+1 esto funciona y proporciona una buena opción para el soporte de little-endian. Me preguntaba si/dónde Java tenía soporte para hacer esto. Sin embargo, crea un objeto para seguir esta ruta. Por lo tanto, no es tan eficiente, aunque dudo que importe para la mayoría de los usos. – WhiteFang34

23

Suponiendo bytes es una byte[4] de un entero con el fin big endian, suele utilizarse en redes:

int value = ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) 
     | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF); 

El & 0xFF son necesarios porque byte se firmará en Java y necesita conservar el bit firmado aquí. Puede invertir el proceso con esta:

bytes[0] = (byte) ((value >> 24) & 0xFF); 
bytes[1] = (byte) ((value >> 16) & 0xFF); 
bytes[2] = (byte) ((value >> 8) & 0xFF); 
bytes[3] = (byte) (value & 0xFF); 
+0

Podría estar malinterpretando, pero creo que eso es lo que escribes. –

+0

@David: es. Gracias, de hecho lo etiqueté mal la primera vez. – WhiteFang34

+2

¿Por qué se necesita el primer '& 0xff' cuando se convierte de' byte [] 'a' int'? ¿No están los primeros 1 para los valores firmados caídos por '<< 24'? Como lo entiendo '((bytes [0] & 0xFF) << 24)' es lo mismo que '((bytes [0] << 24)' en este caso. Si 'byte [0]' está firmado es convertido a int firmado pero '<< 24' lo elimina todo excepto los 8 bits del byte original. También creo que' & 0xff' se usa para soltar los bits iniciales con el valor 1 para los valores firmados para que no tengan ORed a 0 bits de operación anterior. ¿No está diciendo que '& 0xff' es necesario para retener el bit firmado incorrecto? – petrn

6

Es necesario especificar el orden de bytes de la matriz, pero suponiendo que el bytes[0] es el byte más significativo a continuación:

int res = ((bytes[0] & 0xff) << 24) | ((bytes[1] & 0xff) << 16) | 
      ((bytes[2] & 0xff) << 8) | (bytes[3] & 0xff); 

Este código es 100% portable, suponiendo que usa el algoritmo inverso para crear la matriz de bytes en primer lugar. surgen


problemas de orden de bytes en idiomas donde se puede emitidos entre un nativo de tipo entero y el byte tipo de matriz ... y luego descubrir que las diferentes arquitecturas de almacenar los bytes de un entero en diferentes órdenes.

No se puede hacer eso en Java. Entonces, para la comunicación de Java a Java, esto no debería ser un problema.

Sin embargo, si está enviando o recibiendo paquetes a alguna aplicación remota que se implementa en (digamos) C o C++, necesita "saber" qué orden de bytes se está utilizando en los paquetes de red. Algunas estrategias alternativas para saber/calcular esto son:

  • Todo el mundo utiliza "orden de red" (big-endian) para la materia en el alambre de acuerdo con el código de ejemplo anterior. Las aplicaciones que no son Java en máquinas little-endian necesitan voltear los bytes.

  • El emisor averigua el orden que espera el receptor y utiliza ese orden al ensamblar los datos.

  • El receptor averigua qué orden utilizó el emisor (por ejemplo, a través de un indicador en el paquete) y decodifica en consecuencia.

El primer enfoque es más simple y más ampliamente utilizado, aunque da lugar a 2 conversiones endian-ness innecesarios si tanto el emisor como el receptor están ascendente hacia la izquierda.

Ver http://en.wikipedia.org/wiki/Endianness

+0

¿Hay alguna manera de hacer esto a través de la biblioteca estándar? No me siento demasiado bien asumiendo que las cosas son el orden de bytes de las máquinas a las que estoy enviando paquetes ... – Alex

+1

@Alex: el orden de bytes de la máquina no importa en este cálculo, es el orden de bytes de su matriz lo que es importante. Deberá especificarlo incluso si use la biblioteca estándar (si hay un método estándar para hacer esto ... no recuerdo uno). –

+0

Necesita '& 0xFF' cada uno de los bytes porque' byte' está firmado en Java. El bit firmado se interpone en el camino para cualquier número que use el primer bit de cualquiera de los bytes. P.ej. intente ir hacia atrás desde un entero como 384 a una matriz de bytes, cuando ejecute el código para recuperar el entero obtendrá -128 en lugar de 384. – WhiteFang34

4

No estoy seguro si esto es la sintaxis de Java correcto, pero ¿qué tal:

int value = 0; 
for (i = 0; i <= 3; i++) 
    value = (value << 8) + (bytes[i] & 0xFF); 
+2

deberías '0xff' tus' bytes [i] 'porque un' byte' (en Java) puede ser negativo y Java convertirá tu byte en negativo entero en lugar de un valor entre 0-255 –

+0

@Yanick: Gracias. He editado mi publicación con su corrección –

+0

Esto no funciona, siempre devuelve 0. Necesita paréntesis para evitar la precedencia del operador: 'value = (value << 8) + (bytes [i] & 0xFF);' – WhiteFang34

-1
public static int toInt(byte[] bytes) { 
int result = 0; 
for (int i=0; i<3; i++) { 
    result = (result << 8) - Byte.MIN_VALUE + (int) bytes[i]; 
} 
return result; 
} 
+0

Esto no funciona.Una matriz de bytes de todos los ceros devuelve 8421504. – WhiteFang34

+0

¡Es una buena oportunidad! –

1

Asumiendo que su byte [] provienen de algún lugar, por ejemplo, una corriente que puede utilizar

DataInputStream dis = ... // can wrap a new ByteArrayInputStream(bytes) 
int num = dis.readInt(); // assume big-endian. 

o

ByteChannel bc = ... // can be a SocketChannel 
ByteBuffer bb = ByteBuffer.allocate(64*1024); 

bc.read(bb); 
bb.flip(); 
if (bb.remaining()<4) // not enough data 

int num = bb.getInt(); 

Al enviar datos, usted debe saber si va a enviar endian-endian grande o pequeña. Debes asumir otras cosas como si estás enviando un entero con signo de 4 bytes. Un protocolo binario está lleno de suposiciones. (Lo que lo hace más compacto y más rápido, pero más frágil que el texto)

Si no desea hacer tantas suposiciones, envíe un mensaje de texto.

+1

'int num = dis.readInt(); // asumir big-endian. es información muy útil. –

1

también podemos utilizar después para que sea byte más dinámico tamaño de la matriz
Formato BigEndian:

public static int pareAsBigEndianByteArray(byte[] bytes) { 
    int factor = bytes.length - 1; 
    int result = 0; 
    for (int i = 0; i < bytes.length; i++) { 
     if (i == 0) { 
      result |= bytes[i] << (8 * factor--); 
     } else { 
      result |= bytes[i] << (8 * factor--); 
     } 
    } 
    return result; 
} 

pequeño formato Endian:

public static int pareAsLittleEndianByteArray(byte[] bytes) { 
    int result = 0; 
    for (int i = 0; i < bytes.length; i++) { 
     if (i == 0) { 
      result |= bytes[i] << (8 * i); 
     } else { 
      result |= bytes[i] << (8 * i); 
     } 
    } 
    return result; 
} 

Esto le ayuda mucho para la conversión de bytes a int valores

Cuestiones relacionadas