Qual è il metodo migliore per leggere un doppio da un file binario creato in C?
Domanda
Un programma C suddivide i doppi consecutivi in ??un file binario. Vorrei leggerli in Python. Ho provato a usare struct.unpack('d',f.read(8))
EDIT: Ho usato quanto segue in C per scrivere un doppio numero casuale
r = drand48();
fwrite((void*)&r, sizeof(double), 1, data);
Gli errori sono ora corretti ma non riesco a leggere il primo valore. per un numero di tutti 0.000 .. lo legge come 3.90798504668055 ma il resto va bene.
Soluzione
Penso che tu stia leggendo il numero correttamente, ma ti confondi sul display. Quando leggo il numero dal tuo file fornito, ottengo " 3.907985046680551e-14
" - questo è quasi ma non del tutto zero (0,000000000000039 in forma espansa). Sospetto che il tuo codice C lo stia semplicemente stampando con meno precisione di quanto lo sia Python.
[Modifica] Ho appena provato a leggere il file in C e ottengo lo stesso risultato (anche se con una precisione leggermente inferiore: 3.90799e-14) (usando printf ("% g " ;, val)), quindi I pensa che se questo valore non è corretto, è successo sul lato della scrittura, piuttosto che sulla lettura.
Altri suggerimenti
Potresti per favore approfondire " non ha funzionato " ;? Il comando si è bloccato? I dati sono risultati errati? Che cosa è effettivamente successo?
Se il comando si è bloccato:
- Si prega di condividere l'output dell'errore del comando
Se i dati sono semplicemente risultati errati:
-
I sistemi che creano e leggono i dati hanno lo stesso endianness? Se uno è big-endian e l'altro è little-endian, devi specificare una conversione di endianness nella tua stringa di formato.
-
Se l'endianness dei due computer è la stessa, come sono stati scritti i dati nel file, esattamente ? Lo sai? Se lo fai, qual è stato il valore scritto nel file e qual è stato il valore errato che hai ottenuto?
In primo luogo, hai provato pickle ? Nessuno ha ancora mostrato alcun codice Python ... Ecco un po 'di codice per leggere in binario in Python:
import Numeric as N
import array
filename = "tmp.bin"
file = open(filename, mode='rb')
binvalues = array.array('f')
binvalues.read(file, num_lon * num_lat)
data = N.array(binvalues, typecode=N.Float)
file.close()
Dove la f qui specificava numeri a precisione singola, flottanti a 4 byte. Trova le dimensioni dei tuoi dati per voce e utilizzale.
Per i dati non binari potresti fare qualcosa di semplice come questo:
tmp=[]
for line in open("data.dat"):
tmp.append(float(line))
-
f.read (8)
potrebbe restituire meno di 8 byte -
I dati potrebbero avere allineamento e / o endianness diversi:
>>> for c in '@=<>': ... print repr(struct.pack(c+'d', -1.05)) ... '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf' '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf' '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf' '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd' >>> struct.unpack('<d', '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd') (-6.0659880001157799e+066,) >>> struct.unpack('>d', '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd') (-1.05,)
Il miglior metodo sarebbe usare un file di testo ASCII:
0.0
3.1416
3.90798504668055
in quanto sarebbe portatile e funzionerebbe con qualsiasi tipo di implementazione in virgola mobile fino a un certo punto.
La lettura di dati binari non elaborati da un indirizzo di memoria di double
non è affatto portatile ed è destinata a fallire in un'implementazione diversa.
Puoi ovviamente usare un formato binario per compattezza, ma una funzione C portatile che scrive in quel formato non assomiglierebbe affatto al tuo frammento.
Per lo meno, il codice dovrebbe essere circondato da una serie di ifs / ifdefs che verificano che la rappresentazione in memoria di double
utilizzata dalla macchina corrente corrisponda esattamente a quella prevista dall'interprete Python.
Scrivere questo codice sarebbe difficile, motivo per cui sto suggerendo la soluzione semplice, pulita, portatile e leggibile dall'uomo del testo ASCII.
Questa sarebbe la mia definizione di " best " ;.