2009-10-19 23 views
5

Estoy leyendo 8 bytes de datos desde un dispositivo de hardware. Necesito convertirlos en un valor numérico. Creo que quiero convertirlos a uno largo, ya que debería ajustarse a 8 bytes. No estoy muy familiarizado con Java y las operaciones de tipo de datos de bajo nivel. Parece que tengo dos problemas (aparte del hecho de que casi no hay documentación para el hardware en cuestión), los bytes esperan no estar firmados, por lo que no puedo hacer una conversión de entero recto. No estoy seguro de qué endianness son.¿Cómo convierto un byte a un largo en Java?

Cualquier consejo sería apreciado.


Terminamos con esto (tomado de un código fuente que probablemente debería haber leído hace una semana):

public static final long toLong (byte[] byteArray, int offset, int len) 
{ 
    long val = 0; 
    len = Math.min(len, 8); 
    for (int i = (len - 1); i >= 0; i--) 
    { 
     val <<= 8; 
     val |= (byteArray [offset + i] & 0x00FF); 
    } 
    return val; 
} 
+0

¿Por qué necesita convertir esos 8 bytes en un solo valor numérico? Si de hecho son bytes componentes de un valor mayor, entonces no están "firmados" ni "sin firmar". Si no sabes cuál es su endianness, entonces simplemente no puedes interpretarlos como algo de gran valor. –

+0

Sé que son valores sucesivos (un contador magnético) por lo que a través de prueba y error puedo encontrar cuando informa el incremento correcto. Necesito convertirlos a un valor numérico único para determinar su tasa de cambio. – Jotham

+0

Debería reemplazar 0x00FF por 0xFFL ya que eso expresaría mejor su intento de convertir un byte a un largo. – starblue

Respuesta

1

Para el orden de bits, prueba con algunos números que conoces, y luego va a utilizar un desplazamiento de bytes para moverlos a la larga.

Es posible que este sea un punto de partida. http://www.janeg.ca/scjp/oper/shift.html

La dificultad es que dependiendo de la endianess va a cambiar la forma en que lo hace, sino que se desplazará en un 24, 16, 8 y luego añadir la última, básicamente, si el hacer de 32 bits, pero que van más largo, así que haz cambios extra.

+0

Con cambios adicionales, tienes que tener en cuenta que estás cambiando un 'long', no un' int', porque al desplazar más de 24 bits en un 'int' descartarás los bits de mayor orden. – erickson

+0

Dijo que era un largo, así que creo que puede determinar cuántos bits debería ser que realmente necesita. –

4

Byte#longValue() debería hacerlo

Y si no (gracias por la fuente ejemplo) puede usar java.nio.ByteBuffer como en

public static long toLong(byte[] b) { 
    ByteBuffer bb = ByteBuffer.allocate(b.length); 
    bb.put(b); 
    return bb.getLong(); 
} 

La inicial o der es BIG_ENDIAN puede caña more here

+0

Tenía algo así, pero todavía no era bueno. Quizás es porque soy nuevo en Java. public static long bufferToLong (byte [] b) { \t valor largo = b [0]; \t para (int i = 1; i Jotham

+0

¿Para qué sirve el -1? De todos modos, extendí la respuesta para darte quizás otra idea. Por lo que sé - java.nio es bastante rápido (más rápido que tus streams de variedades regulares) – Bostone

+1

Obtengo 'BufferUnderflowException' a menos que llame a' bb.flip(); 'antes de llamar a' getLong() ' –

1

Eche un vistazo a BigInteger (byte []). Es casi lo que quieres, excepto que es uno firmado. Entonces puede agregar un byte más antes de pasarlo a BigInteger.

Otra cosa es que debe saber qué endian son sus bytes.

Espero que esto ayude.

12

El desplazamiento de bytes de acuerdo con la endianidad de los datos es bastante sencillo. Sin embargo, hay un pequeño truco con el tipo de datos long, porque una operación binaria en tipos integrales de int o menor promueve los operandos a int. Para los cambios a la izquierda mayores de 31 bits, esto dará como resultado cero, ya que todos los bits se han desplazado fuera del rango int.

Por lo tanto, la promoción de la fuerza para long mediante la inclusión de un operando long en el cálculo. A continuación, hago esto enmascarando cada byte con el valor 0xFF L, que es un long, forzando el resultado a ser un long.

byte[] buf = new byte[8]; 
/* Fill buf somehow... */ 
long l = ((buf[0] & 0xFFL) << 56) | 
     ((buf[1] & 0xFFL) << 48) | 
     ((buf[2] & 0xFFL) << 40) | 
     ((buf[3] & 0xFFL) << 32) | 
     ((buf[4] & 0xFFL) << 24) | 
     ((buf[5] & 0xFFL) << 16) | 
     ((buf[6] & 0xFFL) << 8) | 
     ((buf[7] & 0xFFL) << 0) ; 
+0

Es posible que desee poner algunos moldes a largo allí ... –

+0

Y tal vez utilizar un índice de matriz que no sea 0. –

+0

Sí, me di cuenta de que a medida que comentaba ... Me ocupé de promocionar a largo en el enmascaramiento – erickson

5

creo que usted podría beneficiarse del uso de java.nio. Así es como se puede almacenar 8 bytes en mucho:

// Byte Array TO Long 
public static long batol(byte[] buff) { 
    return batol(buff, false); 
} 

public static long batol(byte[] buff, boolean littleEndian) { 
    assert(buff.length == 8); 
    ByteBuffer bb = ByteBuffer.wrap(buff); 
    if (littleEndian) bb.order(ByteOrder.LITTLE_ENDIAN); 
    return bb.getLong(); 
}

Por supuesto, los largos resultantes tendrán representación firmado, pero tendrán valores binarios idénticos a los datos de origen.Para una representación de 64 bits + sin signo y aritmático, necesitará usar BigInteger. He aquí cómo convertir de datos "sin firmar" almacenadas en mucho a un BigInteger correcta:

// "Unsigned" Long TO Big Integer 
public static BigInteger ultobi(long ul) { 
    byte[] buff = new byte[8]; 
    ByteBuffer.wrap(buff).asLongBuffer().put(ul); 
    return new BigInteger(+1, buff); 
}
Cuestiones relacionadas