2010-03-04 26 views
57

estoy leyendo un archivo binario como esto:Convertir 4 bytes a int

InputStream in = new FileInputStream(file); 
byte[] buffer = new byte[1024]; 
while((in.read(buffer) > -1) { 

    int a = // ??? 
} 

Lo que quiero hacer es leer hasta 4 bytes y crear un valor int de aquellos pero, no lo creo saber cómo hacerlo

Me siento como si tuviera que tomar 4 bytes a la vez, y llevar a cabo una operación "byte" (como < >> >> < & FF y cosas por el estilo) para crear el nuevo int

¿Cuál es el modismo para esto?

EDITAR

Lamentablemente este llegar a ser un poco más complejo (explicar)

Lo que estoy tratando de hacer es, leer un archivo (puede ser ASCII, binario, que doesn no importa) y extraer los enteros que pueda tener.

Por ejemplo supongamos que el contenido binario (en base 2):

00000000 00000000 00000000 00000001 
00000000 00000000 00000000 00000010 

La representación entera debe ser 1, 2 derecho? : -/1 para los primeros 32 bits, y 2 para los 32 bits restantes.

11111111 11111111 11111111 11111111 

sería -1

y

01111111 11111111 11111111 11111111 

sería Integer.MAX_VALUE (2147483647)

+0

Oh, no ... uno de los muchos alter egos de Oscar está aumentando de nuevo! . –

+1

@SM: Voy a tener que matar sabes – OscarRyz

+1

Una vez que éste por encima de 10k, ¿vas a empezar a borrar las preguntas por sí mismo? : P –

Respuesta

26

Usted debe ponerlo en una función como esta:

public static int toInt(byte[] bytes, int offset) { 
    int ret = 0; 
    for (int i=0; i<4 && i+offset<bytes.length; i++) { 
    ret <<= 8; 
    ret |= (int)bytes[i] & 0xFF; 
    } 
    return ret; 
} 

Ejemplo:

byte[] bytes = new byte[]{-2, -4, -8, -16}; 
System.out.println(Integer.toBinaryString(toInt(bytes, 0))); 

Salida:

11111110111111001111100011110000 

Este se encarga de quedarse sin bytes y correcta manipulación de los valores de byte negativos.

No conozco una función estándar para hacer esto.

cuestiones a considerar:

  1. Endianness: diferentes arquitecturas de CPU ponen los bytes que componen un int en diferentes órdenes. Dependiendo de cómo se le ocurra la matriz de bytes para empezar, tal vez tenga que preocuparse por esto; y

  2. Buffering: si coges 1024 bytes a la vez e inicia una secuencia en el elemento 1022 se alcanzó el final del búfer antes de llegar a 4 bytes.Probablemente sea mejor utilizar alguna forma de flujo de entrada en el búfer que haga el buffer automáticamente para que pueda simplemente usar readByte() repetidamente y no preocuparse de lo contrario;

  3. Trailing Buffer: Al final de la entrada puede haber un número impar de bytes (no un múltiplo de 4 específicamente) según la fuente. Pero si creas la entrada para comenzar y ser un múltiplo de 4 está "garantizado" (o al menos una condición previa), es posible que no necesites preocuparte por ello.

estudiar más en detalle el punto de almacenamiento temporal, considere la BufferedInputStream:

InputStream in = new BufferedInputStream(new FileInputStream(file), 1024); 

Ahora usted tiene una InputStream que automáticamente buffers de 1024 bytes a la vez, lo cual es mucho menos difícil de tratar con. De esta forma, puede leer 4 bytes a la vez y no preocuparse por demasiada E/S.

En segundo lugar, también puede utilizar DataInputStream:

InputStream in = new DataInputStream(new BufferedInputStream(
        new FileInputStream(file), 1024)); 
byte b = in.readByte(); 

o incluso:

int i = in.readInt(); 

y no preocuparse por la construcción de int s en absoluto.

+1

+1, ¡Cuidado con el endianness! –

+0

Solo tengo que considerar el hecho de que mi matriz podría no leer los bytes exactos '% 4' ¿verdad? – OscarRyz

+0

Si la longitud de la matriz no es% 4, puede rellenar los bytes restantes con 0. (Dado que x | 0: = x y 0 << n: = 0). – Pindatjuh

4

intentar algo como esto:

a = buffer[3]; 
a = a*256 + buffer[2]; 
a = a*256 + buffer[1]; 
a = a*256 + buffer[0]; 

esto es suponiendo que el byte más bajo viene primero. si el byte más alto aparece primero, es posible que deba cambiar los índices (pasar de 0 a 3).

básicamente para cada byte que desee agregar, primero multiplique por por 256 (que equivale a un desplazamiento a la izquierda por 8 bits) y luego agregue el nuevo byte.

+2

1, excepto que debe usar en lugar de la multiplicación << – Andrey

+0

A pesar de que conceptualmente de acuerdo con Andrei, yo espero cualquier compilador descenso sería darse cuenta de eso y arreglarlo para usted. Sin embargo, << ES más claro para este propósito. –

+0

@Andrey: para ser justos, el compilador de Java probablemente traducirá 'x * 256' en' x << 8' automáticamente. – cletus

5

La forma más sencilla es:

RandomAccessFile in = new RandomAccessFile("filename", "r"); 
int i = in.readInt(); 

- o -

DataInputStream in = new DataInputStream(new BufferedInputStream(
    new FileInputStream("filename"))); 
int i = in.readInt(); 
+1

suponiendo que su archivo binario contiene grandes firmas firmadas por endian. de lo contrario, fallará. terriblemente. :) – stmax

1
for (int i = 0; i < buffer.length; i++) 
{ 
    a = (a << 8) | buffer[i]; 
    if (i % 3 == 0) 
    { 
     //a is ready 
     a = 0; 
    }  
} 
58

ByteBuffer tiene esta capacidad, y es capaz de trabajar tanto con números enteros pequeños y grandes endian.

Considere este ejemplo:

 

// read the file into a byte array 
File file = new File("file.bin"); 
FileInputStream fis = new FileInputStream(file); 
byte [] arr = new byte[(int)file.length()]; 
fis.read(arr); 

// create a byte buffer and wrap the array 
ByteBuffer bb = ByteBuffer.wrap(arr); 

// if the file uses little endian as apposed to network 
// (big endian, Java's native) format, 
// then set the byte order of the ByteBuffer 
if(use_little_endian) 
    bb.order(ByteOrder.LITTLE_ENDIAN); 

// read your integers using ByteBuffer's getInt(). 
// four bytes converted into an integer! 
System.out.println(bb.getInt()); 
 

Espero que esto ayude.

+0

+1 Ver también http://stackoverflow.com/questions/2211927/converting-long64-to-byte512-in-java – trashgod

+2

+1 Me gusta esta respuesta mucho mejor que la mía. –

13

acaba de ver cómo DataInputStream.readInt() está implementado;

int ch1 = in.read(); 
    int ch2 = in.read(); 
    int ch3 = in.read(); 
    int ch4 = in.read(); 
    if ((ch1 | ch2 | ch3 | ch4) < 0) 
     throw new EOFException(); 
    return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); 
+7

Se debe tener en cuenta que esto es para bytes ordenados de big-endian, donde como soporte para little solo se necesita un pequeño cambio: return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); –

24

Si los tiene ya en una matriz de bytes [], puede utilizar:

int result = ByteBuffer.wrap(bytes).getInt(); 

fuente: here

1

También puede utilizar BigInteger de bytes de longitud variable. Puede convertirlo en Largo, Entero o Corto, según sus necesidades.

new BigInteger(bytes).intValue(); 

o para indicar la polaridad:

new BigInteger(1, bytes).intValue();