Escribí una secuencia de comandos de python para crear un archivo binario de los números enteros.

import struct  
pos = [7623, 3015, 3231, 3829]  
inh = open('test.bin', 'wb')  
for e in pos:  
    inh.write(struct.pack('i', e))  
inh.close()

Funcionó bien, entonces traté de leer la » prueba.bin’ archivo con el siguiente código.

import struct  
inh = open('test.bin', 'rb')  
for rec in inh:  
    pos = struct.unpack('i', rec)  
    print pos  
inh.close()

Pero no con un mensaje de error:

Traceback (most recent call last):   
   File "readbinary.py", line 10, in <module>  
   pos = struct.unpack('i', rec)  
   File "/usr/lib/python2.5/struct.py", line 87, in unpack  
   return o.unpack(s)  
struct.error: unpack requires a string argument of length 4

Me gustaría saber cómo puedo leer estos archivos utilizando struct.unpack.
Muchas gracias de antemano,
Vipin

OriginalEl autor Vipin | 2010-02-16

6 Comentarios

  1. 7

    for rec in inh: , se lee en uno línea en un momento, no lo que usted quiere para un binario archivo. Leer 4 bytes al mismo tiempo (con un while bucle y inh.read(4)) en lugar de (o de leer todo lo que en la memoria con una sola .read() llamada, luego descomprimir sucesivos de 4 bytes en rodajas). El segundo enfoque es más sencillo y más práctico, siempre y cuando la cantidad de datos involucrados no es enorme:

    import struct
    with open('test.bin', 'rb') as inh:
        indata = inh.read()
    for i in range(0, len(data), 4):
        pos = struct.unpack('i', data[i:i+4])  
        print(pos)  

    Si el miedo potencialmente enormes cantidades de datos (que tendría más memoria de la que usted tiene disponibles), un simple generador ofrece una alternativa elegante:

    import struct
    def by4(f):
        rec = 'x'  # placeholder for the `while`
        while rec:
            rec = f.read(4)
            if rec: yield rec           
    with open('test.bin', 'rb') as inh:
        for rec in by4(inh):
            pos = struct.unpack('i', rec)  
            print(pos)  

    Una ventaja clave de este segundo enfoque es que el by4 generador puede ser fácilmente ajustado (mientras que el mantenimiento de las especificaciones: devolver un archivo binario de datos de 4 bytes al mismo tiempo) el uso de otra estrategia de implementación para el almacenamiento en búfer, todo el camino hasta el primer enfoque (leído todo lo que, a continuación, parcela) que puede ser visto como «infinito buffering» y codificados:

    def by4(f):
        data = inf.read()
        for i in range(0, len(data), 4):
            yield data[i:i+4]

    dejando la «lógica de la aplicación» (qué hacer con esa secuencia de 4 bytes trozos) intacto e independiente de la capa de e/S (el cual se encapsula dentro del generador).

    La primera versión de by4 se bloqueará una vez que «rec = f.leer(4)» devuelve cero. No hay salida del bucle while.
    tienes razón — edición de la a a la revisión.
    Una alternativa es el import functools; reader= functools.partial(f.read, 4); for rec in iter(reader, ''): construir. De lo contrario, para evitar functools y su speedup: for rec in iter(lambda: f.read(4), '') )
    En el primer bloque de código, no indata ser data?

    OriginalEl autor Alex Martelli

  2. 4

    Creo «para rec en el inh» se supone que la lectura de «líneas», y no en bytes. Lo que quiero es:

    while True:
        rec = inh.read(4) # Or inh.read(struct.calcsize('i'))
        if len(rec) != 4:
            break
        (pos,) = struct.unpack('i', rec)
        print pos

    O como otros han mencionado:

    while True:
        try:
            (pos,) = struct.unpack_from('i', inh)
        except (some_exception...):
            break

    OriginalEl autor ondra

  3. 1

    Comprobar el tamaño de los paquetes enteros:

    >>> pos
    [7623, 3015, 3231, 3829]
    >>> [struct.pack('i',e) for e in pos]
    ['\xc7\x1d\x00\x00', '\xc7\x0b\x00\x00', '\x9f\x0c\x00\x00', '\xf5\x0e\x00\x00']

    Vemos a 4-cadenas de bytes, esto significa que la lectura debe ser de 4 bytes al mismo tiempo:

    >>> inh=open('test.bin','rb')
    >>> b1=inh.read(4)
    >>> b1
    '\xc7\x1d\x00\x00'
    >>> struct.unpack('i',b1)
    (7623,)
    >>> 

    Este es el original de la int! Se extiende en una lectura de bucle se deja como ejercicio .

    OriginalEl autor gimel

  4. 1

    Usted probablemente puede utilizar array si así lo desea:

    import array  
    pos = array.array('i', [7623, 3015, 3231, 3829]) 
    inh = open('test.bin', 'wb')  
    pos.write(inh)
    inh.close()

    A continuación, utilizar array.array.fromfile o fromstring a la lectura.

    OriginalEl autor u0b34a0f6ae

  5. 1

    Esta función lee todos los bytes del archivo

    def read_binary_file(filename):
    try:
        f = open(filename, 'rb')
        n = os.path.getsize(filename)
        data = array.array('B')
        data.read(f, n)
        f.close()
        fsize = data.__len__()
        return (fsize, data)
    
    except IOError:
        return (-1, [])
    
    # somewhere in your code
    t = read_binary_file(FILENAME)
    fsize = t[0]
    
    if (fsize > 0):
        data = t[1]
        # work with data
    else:
        print 'Error reading file'

    OriginalEl autor roff

  6. 0

    Su iterador no es la lectura de 4 bytes en un tiempo así que me imagino que es más bien confuso. Como SilentGhost se ha mencionado, es probablemente estaría mejor utilizar unpack_from().

    excepto que no hay post de SilentGhost muestra aquí más…

    OriginalEl autor Xorlev

Dejar respuesta

Please enter your comment!
Please enter your name here