PDA

View Full Version : [Linguaggio di scripting qualsiasi] "Lavoretto" su un file binario


Xalexalex
11-08-2012, 19:35
Ciao a tutti!
Per esigenze universitarie mi trovo a lavorare su un file binario prodotto dal data system di un gas cromatografo. Cio' che devo estarvi e' un semplice cromatogramma, che per quanto ci interessa e' una grafico di una qualche intensita' in funzione del tempo.

Quello che sputa il programma fuori e' un file binario, che contiene:
- una parte di intestazione;
- una parte che contiene i dati, fatta cosi:
http://i46.tinypic.com/tzec2.png
Io la interpreto questo modo: quattro doppiette di numeri fanno un'intensita'. Il file non specifica a che tempo viene preso il dato, perche' assume di prendere il primo dato a t=0, poi campiona un dato ogni secondo.
- una parte di chiusura.

Ora, quello che dovrei fare io e' prendere uno di questi file, aprirlo, strippare via la parte di intestazione (eventualmente recuperando qualche informazione, convertendola in testo), poi prendere la parte dei dati effettivi e convertirla in un file csv.

Mi date un aiutino su come potrei fare? :help:
Conoscicchio il PHP e non ho problemi a metter su un server locale per fare il lavoro, ma non so se con quello si possa fare.
Ale

demos88
11-08-2012, 20:11
Io la interpreto questo modo: quattro doppiette di numeri fanno un'intensita'. Il file non specifica a che tempo viene preso il dato, perche' assume di prendere il primo dato a t=0, poi campiona un dato ogni secondo.

L'interpretazione secondo te è giusta? i dati sono quasi tutti uguali, è il risultato atteso?

Conoscicchio il PHP e non ho problemi a metter su un server locale per fare il lavoro, ma non so se con quello si possa fare.
Ale
E' fattibile in PHP, ma è uno degli ultimi linguaggi sulla faccia della terra che mi verrebbe in mente di usare in questo caso :asd:
Comunque è fattibile con tutti i linguaggi che permettono di leggere un file, ovvero una infinità :asd:
Java, C#, Python, C, C++...

Xalexalex
11-08-2012, 21:20
L'interpretazione secondo te è giusta? i dati sono quasi tutti uguali, è il risultato atteso?

E' fattibile in PHP, ma è uno degli ultimi linguaggi sulla faccia della terra che mi verrebbe in mente di usare in questo caso :asd:
Comunque è fattibile con tutti i linguaggi che permettono di leggere un file, ovvero una infinità :asd:
Java, C#, Python, C, C++...

Ce n'e' un'infinita' di quei "blocchi di dati", quello che vedi e' solo l'inizio: ci sta che sia tutto uguale perche' la linea di base inizia... dritta. :D Scorrendo il file si vede che i valori aumentano durante i (supposti) picchi cromatografici, per poi tornare ad un valore grossomodo uguale a quello che si vede in partenza (non proprio uguale, e' un drift fisiologico della linea di base).

Quello che mi manca e' capire come fare ad aprire il file "in binario", e a leggere i blocchi di quattro doppiette. Che poi non so se aprendolo il binario il file legga le doppiette esadecimali. Leggera' il binario, no? :sofico:

cdimauro
12-08-2012, 06:38
In Python è banale. Ti faccio alcuni esempi:
import struct # Importo il modulo che mi consente di manipolare strutture C-like

struct.unpack('4f', '\x00\x00\x25\x9d\x00\x00\x05\xb4\x00\x00\x05\xb3\x00\x00\x05\xb3')
struct.unpack('4i', '\x00\x00\x25\x9d\x00\x00\x05\xb4\x00\x00\x05\xb3\x00\x00\x05\xb3')
struct.unpack('>4i', '\x00\x00\x25\x9d\x00\x00\x05\xb4\x00\x00\x05\xb3\x00\x00\x05\xb3')
L'output rispettivamente è:
(-2.183756817139993e-21, -1.2386590242385864e-07, -3.096647560596466e-08, -3.096647560596466e-08)
(-1658519552, -1274740736, -1291517952, -1291517952)
(9629, 1460, 1459, 1459)
perché ho chiesto di interpretare i 16 byte come 4 float (virgola mobile a 32 bit), 4 interi (a 32 bit, con segno), e 4 interi in formato big-endian (a 32 bit, con segno, il byte più significativo è il primo e il meno significativo è l'ultimo / quarto).

Ti scrivo 2 righe al volo per fare lo stesso con un file:
import struct

f = open('ee_003.raw', 'rb') # r = lettura, b = binario
f.seek(0x3d0) # Mi posiziono dopo l'intestazione, per iniziare a leggere i dati veri e propri
s = f.read(16) # Leggo 16 byte
Quartetto = struct.unpack('4f', s) # Spacchetto 4 valori dai 16 byte letti. Il risultato è una tupla (una sorta di array a sola lettura)
print Quartetto[0] # Primo valore
print Quartetto[3] # Quarto valore

P.S. Python è molto usato anche in ambito di hacking ormai. ;)

Xalexalex
12-08-2012, 08:09
In Python è banale. Ti faccio alcuni esempi:
import struct # Importo il modulo che mi consente di manipolare strutture C-like

struct.unpack('4f', '\x00\x00\x25\x9d\x00\x00\x05\xb4\x00\x00\x05\xb3\x00\x00\x05\xb3')
struct.unpack('4i', '\x00\x00\x25\x9d\x00\x00\x05\xb4\x00\x00\x05\xb3\x00\x00\x05\xb3')
struct.unpack('>4i', '\x00\x00\x25\x9d\x00\x00\x05\xb4\x00\x00\x05\xb3\x00\x00\x05\xb3')
L'output rispettivamente è:
(-2.183756817139993e-21, -1.2386590242385864e-07, -3.096647560596466e-08, -3.096647560596466e-08)
(-1658519552, -1274740736, -1291517952, -1291517952)
(9629, 1460, 1459, 1459)
perché ho chiesto di interpretare i 16 byte come 4 float (virgola mobile a 32 bit), 4 interi (a 32 bit, con segno), e 4 interi in formato big-endian (a 32 bit, con segno, il byte più significativo è il primo e il meno significativo è l'ultimo / quarto).

Ti scrivo 2 righe al volo per fare lo stesso con un file:
import struct

f = open('ee_003.raw', 'rb') # r = lettura, b = binario
f.seek(0x3d0) # Mi posiziono dopo l'intestazione, per iniziare a leggere i dati veri e propri
s = f.read(16) # Leggo 16 byte
Quartetto = struct.unpack('4f', s) # Spacchetto 4 valori dai 16 byte letti. Il risultato è una tupla (una sorta di array a sola lettura)
print Quartetto[0] # Primo valore
print Quartetto[3] # Quarto valore

P.S. Python è molto usato anche in ambito di hacking ormai. ;)

A 'sto punto mi installo l'interprete python e ci gioco un pochino.
Un grazie sentititissimo, considera una birra pagata. :D
Alex

Xalexalex
12-08-2012, 09:36
Dopo una mezz'oretta di smanetto: http://tinypic.com/r/atu9hl/6
So' soddisfazioni, sono riuscito a fare uno scriptino che mi parsa in batch tutta una cartella. In due minuti mi sono risparmiato un viaggio (fisico) fino a Pisa.

Grazie ancora a tutti :D

cdimauro
12-08-2012, 10:33
:eek: Instant Python. :D

Quindi in questa mezz'oretta hai pure avuto modo di smanettare col modulo glob per leggere l'elenco dei file di una cartella e, da quel che vedo nell'immagine, pure con quello csv.


Che dire: complimenti anche a te. :)

Xalexalex
12-08-2012, 11:29
:eek: Instant Python. :D

Quindi in questa mezz'oretta hai pure avuto modo di smanettare col modulo glob per leggere l'elenco dei file di una cartella e, da quel che vedo nell'immagine, pure con quello csv.


Che dire: complimenti anche a te. :)
Ma di che :D Per leggere i file dalla cartella ho usato il modulo os, mentre per il csv... ho fatto a mano. :asd:

Qui il codice, per la cronaca

import os
import sys
import struct


## Definizione della funzione converti
def converti (filename):
"Questa funzione effettua la conversione"
f = open(filename, 'rb') # r = lettura, b = binario
f.seek(0x300) # Mi posiziono circa alla fine dell'intestazione

#Cerco il segno di inizio (00 00 00 09) e mi sposto 16x4 byte dopo
while 1:
z = f.read(4)
scarto = struct.unpack('>i', z)
if scarto[0] == 9:
f.seek(64,1)
break

sc = open(filename+'.csv','w')
sc.write('RT(milliseconds);RT(minutes) - NOT USED BY IMPORT;RI;100\n')

sec = 0
while 1:
s = f.read(4) # Leggo 4 byte
valore = struct.unpack('>i', s) # Spacchetto 1 valore dai 4 byte letti, il ris. va in [0] di una tupla.
if valore[0] == 4:
break
sc.write(str(sec)+";0;0.0;"+str(valore[0])+"\n") # Primo valore
sec=sec+200

sc.close()
f.close()
return

####
if len(sys.argv) == 1:
for files in os.listdir("."):
if files.endswith(".raw"):
converti(files)
else:
converti(sys.argv[1])



Ad essere sincero mi rimane un dubbio: non c'e' altro modo di leggere i quattro byte in binario, se non con struct.unpack? A logica mi pare poco sensato dovere mettere un dato in una tupla che contiene un solo elemento, invece che in una variabile semplice.

cdimauro
12-08-2012, 11:53
Ti capisco, ma la logica di unpack è di interpretare una sequenza di byte e restituire una sequenza di dati (definiti nella stringa di formattazione).

Per cui è logico che restituisca una tupla, che in Python identifica, appunto, una sequenza di informazioni (eterogenee per tipo).

Per il resto il codice che hai scritto è ben strutturato, e ho visto che ti sei dato da fare per risolvere i sottoproblemi che ti sono presentati. Per essere il primo programma che scrivi in Python, sei messo decisamente bene; puoi migliorare un po' guardando la libreria standard di Python, che ha parecchia roba interessante che ti mette già a disposizione, senza che debba reinventarti la ruota.

Xalexalex
12-08-2012, 12:36
Infatti, provero' a utilizzare il modulo csv e magari provo ad interpretare parte dell'intestazione per produrre un file completo.
Grazie ancora! :D

cdimauro
12-08-2012, 13:25
A stomaco pieno si ragiona meglio. :D

Se sei sicuro che la tupla ritornata abbia un solo elemento, potresti utilizzare l'operatore di tuple/list-unpacking.

Nel tuo caso, ad esempio:
scarto, = struct.unpack('>i', z)
if scarto == 9:
Da notare la virgola dopo la variabile scarto. Serve a indicare la presenza di una sequenza di variabili che dovranno accogliere i valori presenti nella tupla o lista a destra dell'assegnazione.

Ovviamente nel caso in cui i valori fossero più d'uno, avresti qualcosa del tipo:
x, y, z = (1, 2, 3)

Si tratta di un costrutto molto usato in Python. Comodissimo per "spacchettare" tuple, liste, e in generale qualunque tipo di dati che è possibile trattare come "sequenza".