PDA

View Full Version : [JAVA] Lettura dati binari interi a 32-bit


DeltaDirac
26-03-2011, 18:38
Ciao,

vorrei un consiglio per leggere in JAVA dei dati binari in uscita da un AD converter di uno strumento di misura. Non conosco molto bene il linguaggio e la difficoltà principale che incontro è nella corretta lettura del formato binario.

Lo strumento è basato su piattaforma Intel x86, quindi i dati sono salvati in memoria in formato little-endian come signed int a 32 bit.

Ho tentato vari approcci con DataInputStream, BufferedReader, metodo read() diretto... ma non riesco ad ottenere una lettura corretta: ottengo valori pazzi, molto alti o zero, quando il contenuto del file binario è di altro tipo.

Esiste una macro interna allo strumento che esporta i dati in formato ASCII e dal confronto mi rendo conto dell'errore.

Questa è la classe ReadBin che ho tentato di utilizzare:


// ReadBin.java
import java.io.DataInputStream;
import java.io.FileInputStream;

public class ReadBin {

public static void main(String args[]) {
try {

// Crea un data input stream
FileInputStream fis = new FileInputStream("fileName.dat");
DataInputStream dis = new DataInputStream(fis);

// Legge i primi venti dati dallo stream
for (int t=0; t<20; t++)
System.out.println(dis.readByte());

// Chiude il file input stream
fis.close();
} catch (Exception e)
{
System.out.println("Exception: " + e);
}
}
}



Il file binario è fileName.dat, che consta di 65536 dati di 4 bytes l'uno.

Al seguente LINK è reperibile il file fileName.zip che contiene il file binario (fileName.dat) e il file in formato ascii (fileName.txt).


http://dl.dropbox.com/u/21541796/fileName.zip


Grazie per ogni buon lume ;)
DD

VICIUS
27-03-2011, 09:27
In ObjectInputStream c'è una funzione che permette di leggere gli int. Non ricordo però se li legge big-endian o little-endian. Prova e vedi se i valori sono corretti.

PGI-Bis
27-03-2011, 11:42
L'ordine dei byte in datainputstream è quello di java (big endian).

Strano a dirsi ma una valida alternativa è FileImageInputStream.

FileImageInputStream fin = new FileImageInputStream(new File("filename.dat"));
fin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
for(int i = 0; i < 20; i++) {
int numero = fin.readInt();
}

PS: Al file in formato ascii mancano un tot di righe (le prime 1722 ad essere precisi).

DeltaDirac
27-03-2011, 18:38
L'ordine dei byte in datainputstream è quello di java (big endian).

Strano a dirsi ma una valida alternativa è FileImageInputStream.

FileImageInputStream fin = new FileImageInputStream(new File("filename.dat"));
fin.setByteOrder(ByteOrder.LITTLE_ENDIAN);
for(int i = 0; i < 20; i++) {
int numero = fin.readInt();
}

PS: Al file in formato ascii mancano un tot di righe (le prime 1722 ad essere precisi).

Si, grazie per la precisazione: non so spiegarmene il motivo ma l'upload del file *txt è andato male.

Questo è il nuovo link (http://dl.dropbox.com/u/21541796/fileName.zip) in cui compaiono entrambi i file (binario e formato testo) con le dimensioni corrette.


Venendo al nocciolo della questione: tu dici che l'ordine dei byte in JAVA è big-endian. E' un'asserzione notevole, e l'unica spiegazione che vedo e nella gestione del formato dei dati operato dalla JVM che per qualche ragione è diversa da quella nativa della CPU Intel (little endian). Ma nella documentazione non sono riuscito a scovare questa informazione; mi puoi indicare dove trovarla?

Comunque confermo: usando la classe FileImageInputStream tutto funziona a dovere. Grazie ;)

Ovviamente occorre importare correttamente i pack e le classi relative.

Ho modificato il sorgente così:


// ReadBin.java
import java.io.File;
import javax.imageio.stream.FileImageInputStream;
import java.nio.ByteOrder;

public class ReadBin {

public static void main(String args[]) {
try {

// Crea un FileImage input stream
FileImageInputStream fis = new FileImageInputStream(new File("fileName.dat"));

// Converte in LITTLE_ENDIAN
fis.setByteOrder(ByteOrder.LITTLE_ENDIAN);

// Legge i primi venti dati dallo stream
for (int t=0; t<20; t++)
System.out.println(fis.readInt());

// Chiude il file input stream
fis.close();
} catch (Exception e)
{
System.out.println("Exception: " + e);
}
}
}


Non ci sarei mai arrivato da solo.
Grazie ancora.

PGI-Bis
27-03-2011, 20:34
La jvm è big-endian per via del capitolo 3.11 delle sue specifiche (operandi multibyte).

Per quanto riguarda il linguaggio, sebbene sia comunemente considerato big-endian solo per convenzione, l'ordine è - a mio sommessissimo parere - chiaramente espresso nelle specifiche del linguaggio (3.10.1) relativamente alle corrispondenze esadecimale-decimale - i corrispondenti esadecimali degli interi multibyte sono tutti big-endian.

Presumo che la ragione dipenda dal fatto che java è nato come strumento per il web e che quindi si sia scelto di adottare il formato "network byte order", cioè il big endian.

DeltaDirac
28-03-2011, 09:03
Prefetto, grazie!