Iterador de archivos Python sobre un archivo binario con un lenguaje más reciente


En Python, para un archivo binario, puedo escribir esto:

buf_size=1024*64           # this is an important size...
with open(file, "rb") as f:
   while True:
      data=f.read(buf_size)
      if not data: break
      # deal with the data....

Con un archivo de texto que quiero leer línea por línea, puedo escribir esto:

with open(file, "r") as file:
   for line in file:
       # deal with each line....

Que es la abreviatura de:

with open(file, "r") as file:
   for line in iter(file.readline, ""):
       # deal with each line....

Este modismo está documentado en PEP 234 pero no he podido localizar un modismo similar para archivos binarios.

He intentado esto:

>>> with open('dups.txt','rb') as f:
...    for chunk in iter(f.read,''):
...       i+=1

>>> i
1                # 30 MB file, i==1 means read in one go...

Intenté poner iter(f.read(buf_size),'') pero eso es un error de sintaxis debido a los paréntesis después del invocable en iter().

Sé que podría escribir un función, pero ¿hay alguna manera con el modismo predeterminado de for chunk in file: donde puedo usar un tamaño de búfer frente a una línea orientada?

Gracias por soportar al novato de Python intentando escribir su primer script Python no trivial e idiomático.

Author: dawg, 2010-12-31

2 answers

No conozco ninguna forma incorporada de hacer esto, pero una función wrapper es bastante fácil de escribir:

def read_in_chunks(infile, chunk_size=1024*64):
    while True:
        chunk = infile.read(chunk_size)
        if chunk:
            yield chunk
        else:
            # The chunk was empty, which means we're at the end
            # of the file
            return

Luego en el prompt interactivo:

>>> from chunks import read_in_chunks
>>> infile = open('quicklisp.lisp')
>>> for chunk in read_in_chunks(infile):
...     print chunk
... 
<contents of quicklisp.lisp in chunks>

Por supuesto, puede adaptar esto fácilmente para usar un bloque con:

with open('quicklisp.lisp') as infile:
    for chunk in read_in_chunks(infile):
        print chunk

Y puedes eliminar la sentencia if como esta.

def read_in_chunks(infile, chunk_size=1024*64):
    chunk = infile.read(chunk_size)
    while chunk:
        yield chunk
        chunk = infile.read(chunk_size)
 21
Author: Jason Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-31 04:16:21

Intenta:

>>> with open('dups.txt','rb') as f:
...    for chunk in iter((lambda:f.read(how_many_bytes_you_want_each_time)),''):
...       i+=1

iter necesita una función con cero argumentos.

  • una llanura f.read leería todo el archivo, ya que falta el parámetro size;
  • {[6] } significa llamar a una función y pasar su valor de retorno (datos cargados desde el archivo) a iter, por lo que iter no obtiene una función en absoluto;
  • (lambda:f.read(1234)) es una función que toma cero argumentos (nada entre lambda y :) y llama a f.read(1234).

Hay equivalencia entre lo siguiente:

somefunction = (lambda:f.read(how_many_bytes_you_want_each_time))

Y

def somefunction(): return f.read(how_many_bytes_you_want_each_time)

Y teniendo uno de estos antes de tu código podrías escribir: iter(somefunction, '').

Técnicamente puedes saltarte los paréntesis alrededor de lambda, la gramática de python aceptará eso.

 33
Author: liori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-11 21:48:48