online - Abrir archivo, leerlo, procesarlo y volver a escribirlo-el método más corto en Python
python package naming conventions (6)
Quiero hacer algunos filtros básicos en un archivo. Léelo, hazlo, escríbelo.
No estoy buscando "jugar al golf", pero quiero el método más simple y elegante para lograrlo. Se me ocurrio:
from __future__ import with_statement
filename = "..." # or sys.argv...
with open(filename) as f:
new_txt = # ...some translation of f.read()
open(filename, ''w'').write(new_txt)
La instrucción with
hace que las cosas sean más cortas ya que no tengo que abrir y cerrar explícitamente el archivo.
¿Alguna otra idea?
Esto parece funcionar:
with open(filename, "r+") as f:
new_txt = process(f.read())
f.truncate(0)
f.write(new_txt)
Si está buscando el equivalente de python "perl -pi", aquí hay uno bastante bueno:
import fileinput for line in fileinput.input(): # process line
Consulte http://www.python.org/doc/2.5.2/lib/module-fileinput.html para obtener más información.
Hecho de esta manera, usaría su secuencia de comandos python en una tubería para crear el nuevo archivo:
$ myscript.py infile.txt > outfile.txt
Para hacerlo de una manera que no comerá sus datos si se bloquea en el medio:
from twisted.python.filepath import FilePath
p = FilePath(filename)
p.setContent(process(p.getContent()))
En realidad, una forma más sencilla de usar la entrada de archivo es usar el parámetro inplace:
import fileinput
for line in fileinput.input (filenameToProcess, inplace=1):
process (line)
Si usa el parámetro inplace, redireccionará stdout a su archivo, de modo que si imprime, lo volverá a escribir en su archivo.
Este ejemplo agrega números de línea a su archivo:
import fileinput
for line in fileinput.input ("b.txt",inplace=1):
print "%d: %s" % (fileinput.lineno(),line),
Mi fea (pero corta como se dice en la pregunta) solución con expresiones de generador ;
# Some setup first
file(''test.txt'', ''w'').write(''/n''.join(''%05d'' % i for i in range(100)))
# This is the filter function
def f(i):
return i % 3
# This is the main part
file(''test2.txt'', ''w'').write(''/n''.join(str(f(int(l))) for l in file(''test.txt'', ''r'').readlines()))
# And a wrapper for sanity
def filter_file(infile, outfile, filter_function)
outfile.write(''/n''.join(filter_function(l) for l in infile.readlines()))
Me gustaría ir por la elegancia de una manera diferente: implemente las operaciones de lectura y filtrado de archivos como generadores, escribirá más líneas de código, pero será un código más flexible, mantenible y de rendimiento.
Vea los Trucos de generadores para programadores de sistemas de David M. Beazley, que es algo realmente importante para cualquier persona que escriba este tipo de código para leer.