2009-03-10 13 views
5

Un programa C crea dobles consecutivos en un archivo binario. Deseo leerlos en Python. He intentado utilizar struct.unpack('d',f.read(8))¿Cuál es el mejor método para leer un doble de un archivo binario creado en C?

EDIT: He utilizado el siguiente en C para escribir un número aleatorio doble

r = drand48(); 
fwrite((void*)&r, sizeof(double), 1, data); 

los errores ya están resueltos, pero no puedo leer el primer valor. para un número de 0.000, lo lee como 3.90798504668055, pero el resto está bien.

+0

Podría estar conectado con un endosamiento incorrecto (lo que viene primero es el byte menos significativo o no). Muestra qué bytes estás tratando de leer. – jfs

+0

Lo siento. Casi soluciono el problema, así que lo marqué como respondido. Me gustaría ver el primer número leído correctamente. – gnosio

+0

¿Puede proporcionar un volcado de los primeros 40 bytes del archivo junto con el código que está utilizando actualmente para leerlo? –

Respuesta

3

Creo que en realidad se está leyendo el número correctamente, pero no están muy por la pantalla. Cuando leo el número de su archivo provisto, obtengo "3.907985046680551e-14" - esto es casi pero no exactamente cero (0.000000000000039 en forma expandida). Sospecho que tu código C solo está imprimiéndolo con menos precisión que python.

[Editar] Acabo de intentar leer el archivo en C, y obtengo el mismo resultado (aunque con un poco menos de precisión: 3.90799e-14) (usando printf ("% g", val)), entonces piense que si este valor es incorrecto, sucedió en el lado de la escritura, en lugar de la lectura.

+0

Hola Brian, lo has clavado. Fui flojo para expandirlo :(. La precisión es la razón de 2 valores diferentes. Gracias por la ayuda. – gnosio

1

¿Podría detallar "no funcionó"? ¿Se bloqueó el comando? ¿Los datos salieron mal? ¿Lo que realmente pasó?

Si el comando se estrelló:

  • favor comparta la salida de error del comando

Si los datos simplemente salieron mal:

  • ¿Los sistemas que crean y leer los datos tienen el mismo endianness? Si uno es big-endian y el otro es little-endian, entonces necesita especificar una conversión de endianness en su cadena de formato.

  • Si la endianidad de las dos computadoras es la misma, ¿cómo se escribieron los datos en el archivo, exactamente? ¿Tú sabes? Si lo hace, ¿cuál fue el valor escrito en el archivo y cuál fue el valor incorrecto que obtuvo?

0
  • f.read(8) podría devolver menos de 8 bytes
  • de datos pueden tener diferentes alineación y/o orden de bits:

    >>> 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,) 
    
0

El mejor método sería utilizar una Archivo de texto ASCII:

0,0
3,1416
3,90798504668055

en que sería portátil y funciona con cualquier tipo de aplicación flotante punto hasta cierto punto.

La lectura de datos binarios sin procesar desde una dirección de memoria double no es portátil en absoluto, y es probable que falle en alguna implementación diferente.

Por supuesto, puede utilizar un formato binario para compacidad, pero una función C portátil escribiendo en ese formato no se parecería en absoluto a su fragmento.

Como mínimo, el código debe estar rodeado por una serie de ifs/ifdefs que comprueben que la representación de memoria de double utilizada por la máquina actual coincide exactamente con la esperada por el intérprete de Python.

Escribir dicho código sería difícil, por lo que sugiero la solución fácil, limpia, portátil y legible para humanos de texto ASCII.

Esto sería my definición de "mejor".

+0

Hola Aib, ojalá pudiera hacer eso, pero es un tugurio de memoria y no tengo control sobre cómo se exporta. Estoy teniendo un buen éxito con el desempaquetado, pero por alguna razón no lee correctamente el primer Doble. – gnosio

+0

Lo había adivinado, pero todavía quería hacer mi punto para futuros lectores. Me alegra que hayas resuelto tu problema. – aib

1

En primer lugar, ¿has probado pickle? Nadie ha mostrado ningún código Python sin embargo ... Aquí hay un código para leer en binario en 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() 

Cuando la f aquí especificado de precisión simple, de 4 bytes flotantes, números. Encuentra el tamaño de tus datos por entrada y usa eso.

Para los datos binarios no se podría hacer algo tan simple como esto:

tmp=[] 
    for line in open("data.dat"): 
       tmp.append(float(line)) 
+0

Oye, Alex, intenté encurtir pero para mi problema no estoy seguro de que todos los valores sean Dobles. Podrían ser Ints, Flotas o Dobles. Todo lo que sé es la ubicación y el tipo de valor para leer. Gracias por la ayuda :) – gnosio

Cuestiones relacionadas