2010-03-04 20 views
57

Sto leggendo un file binario come questo:Convertire 4 byte a int

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

    int a = // ??? 
} 

Quello che voglio fare per leggere fino a 4 byte e creare un valore int da quelli ma, non lo faccio sapere come farlo

I sorta di sento come se avessi di afferrare 4 byte alla volta, ed eseguire un'operazione "byte" (come >> < < >> & FF e cose del genere) per creare la nuova int

Qual è l'idioma per questo?

EDIT

Ops questo rivelarsi un po 'più complesso (da spiegare)

Quello che sto cercando di fare è, leggere un file (può essere ascii, binario, doesn importa) ed estraete i numeri interi che potrebbe avere.

Ad esempio si supponga che il contenuto binario (in base 2):

00000000 00000000 00000000 00000001 
00000000 00000000 00000000 00000010 

La rappresentazione intera dovrebbe essere 1, 2 giusto? : -/1 per i primi 32 bit e 2 per i restanti 32 bit.

11111111 11111111 11111111 11111111 

sarebbe -1

e

01111111 11111111 11111111 11111111 

sarebbe Integer.MAX_VALUE (2147483647)

+0

Oh no ... uno dei tanti alter ego di Oscar è in aumento di nuovo! . –

+1

@SM: dovrò uccidere lo sai – OscarRyz

+1

Una volta ottenuto questo sopra 10k, inizierai a eliminare le domande da solo? : P –

risposta

26

Si dovrebbe mettere in una funzione come questa:

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; 
} 

Esempio:

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

uscita:

11111110111111001111100011110000 

Questo si prende cura di esaurimento di byte e corretta movimentazione valori di byte negativi.

Non sono a conoscenza di una funzione standard per farlo.

problemi da considerare:

  1. Endianness: diverse architetture CPU mettono i byte che compongono un int in ordine diverso. A seconda di come si presenta la matrice di byte all'inizio, potrebbe essere necessario preoccuparsi di ciò; e

  2. buffering: se si afferra 1024 byte alla volta e iniziare una sequenza a elemento 1022 vi ha colpito la fine del buffer prima di ottenere 4 byte.Probabilmente è meglio usare qualche forma di stream di input bufferizzato che esegue automaticamente il buffering in modo da poter usare ripetutamente lo readByte() e non preoccuparsi altrimenti;

  3. Buffer di coda: la fine dell'input può essere un numero dispari di byte (non un multiplo di 4 in particolare) a seconda della sorgente. Ma se crei l'input per cominciare e se un multiplo di 4 è "garantito" (o almeno una precondizione) potresti non aver bisogno di occupartene.

di elaborare ulteriormente sul punto di buffering, considerano la BufferedInputStream:

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

Ora avete un InputStream che automaticamente buffer 1024 byte alla volta, che è molto meno difficile da avere a che fare con. In questo modo puoi leggere felicemente 4 byte alla volta e non preoccuparti di troppo I/O.

In secondo luogo è anche possibile utilizzare DataInputStream:

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

o anche:

int i = in.readInt(); 

e non preoccuparsi di costruire int s affatto.

+1

+1, Attenzione per l'endianità! –

+0

Devo solo considerare il fatto che il mio array potrebbe non leggere esattamente i byte '% 4' giusto? – OscarRyz

+0

Se la lunghezza dell'array non è% 4, è possibile eseguire il pad dei byte rimanenti con 0. (Poiché x | 0: = x e 0 << n: = 0). – Pindatjuh

4

provare qualcosa di simile:

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

questo è supponendo che il byte più basso viene prima. se il byte più alto viene prima, potrebbe essere necessario scambiare gli indici (andare da 0 a 3).

fondamentalmente per ogni byte che si desidera aggiungere, prima moltiplicare a per 256 (che equivale a uno spostamento a sinistra di 8 bit) e quindi aggiungere il nuovo byte.

+2

+1 eccetto che dovresti usare << invece della moltiplicazione – Andrey

+0

Anche se concordo concettualmente con Andrey, mi auguro che qualsiasi compilatore di discesa lo capisca e lo risolva per te. Tuttavia, << È più chiaro per questo scopo. –

+0

@Andrey: per essere onesti, il compilatore Java probabilmente tradurrà 'x * 256' in' x << 8' automaticamente. – cletus

5

Il modo più semplice è:

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

partendo dal presupposto che il suo file binario contenga caratteri firmati big endian. altrimenti fallirà. orribilmente. :) – 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 ha questa capacità, ed è in grado di lavorare con entrambi interi piccoli e grandi endian.

Considerate questo esempio:

 

// 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()); 
 

Spero che questo aiuti.

+0

+1 Vedi anche http://stackoverflow.com/questions/2211927/converting-long64-to-byte512-in-java – trashgod

+2

+1 Mi piace questa risposta molto meglio della mia. –

13

basta vedere come DataInputStream.readInt() è implementato;

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

Si noti che questo è per i byte ordinati big-endian, dove il supporto per pochi richiede solo una piccola modifica: return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); –

24

Se li avete già in un byte [] array, è possibile utilizzare:

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

fonte: here

1

È inoltre possibile utilizzare BigInteger per i byte di lunghezza variabile. Puoi convertirlo in Long, Integer o Short, a seconda delle tue esigenze.

new BigInteger(bytes).intValue(); 

o per indicare la polarità:

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