2010-12-30 31 views
20

En Python, para un archivo binario, que puede escribir lo siguiente:archivo Python iterador sobre un archivo binario con nuevos modismo

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, lo que pueda escribir esto:

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

Cuál es la abreviatura:

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

este idioma se documenta en PEP 234 pero tengo Faile d para 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... 

He intentado poner iter(f.read(buf_size),'') pero eso es un error de sintaxis debido a los parens después de la exigible en el iter().

Sé que podría escribir una función, pero ¿hay forma de utilizar el idioma por defecto for chunk in file: donde puedo usar un tamaño de buffer frente a una línea?

Gracias por aguantar al novato de Python al intentar escribir su primer guion Python no trivial e idiomático.

Respuesta

20

no sé de ninguna manera integrada para realizar esta acción, sino una función de contenedor es lo suficientemente 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 

A continuación, en el modo 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> 

De Por supuesto, puede adaptarlo fácilmente para usar un bloque con:

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

Y puede eliminar la instrucción 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) 
+0

Supuse que había alguna forma incorporada que solo estaba pasando por alto. Dado que parece no haber una forma integrada, esto es fácil de leer y sencillo. ¡Gracias! – dawg

30

Probar:

>>> 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 que leer todo el archivo, ya que el parámetro es size faltante;
  • 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 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).

existe una equivalencia entre el 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 tener uno de estos antes de su código que acaba podría escribir: iter(somefunction, '').

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

+0

Sí, el truco centinela con iter() es realmente bueno! (Aunque no me gustan las lambdas, entonces habría hecho una función). –

+0

¡Eso funciona! Gracias. Es difícil perder viejos modismos (Perl) y aprender otros nuevos mientras se sigue siendo razonablemente productivo. – dawg

+0

Esto funciona ... pero es un poco difícil de leer en mi opinión. –

Cuestiones relacionadas