Itinerador de archivos de Python sobre un archivo binario con un nuevo idioma.

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 taquigrafía para:

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

Este idioma está documentado en PEP 234 pero no he podido localizar un idioma 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 syntax debido a los parens después de la llamada en iter ().

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

Gracias por aguantar al novato de Python que intenta escribir su primer script de Python no trivial e idiomático.

No conozco ninguna forma integrada de hacer esto, pero una función de envoltorio 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 indicador interactivo:

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

Por supuesto, puedes adaptarlo fácilmente para usar un bloque with:

 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) 

Tratar:

 >>> 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.

  • un f.read normal f.read todo el archivo, ya que falta el parámetro de size ;
  • f.read(1024) 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 ninguna función;
  • (lambda:f.read(1234)) es una función que toma cero argumentos (nada entre lambda y f.read(1234) y llama a f.read(1234) .

Hay equivalencia entre las siguientes:

 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 su código, simplemente podría escribir: iter(somefunction, '') .

Técnicamente puede omitir los paréntesis alrededor de lambda, la gramática de python lo aceptará.