2010-12-15 10 views
47

Necesito agregar una sola línea a la primera línea de un archivo de texto y parece que las únicas opciones disponibles para mí son más líneas de código de las que esperaría de python. Algo como esto:Anteponer una línea a un archivo existente en Python

f = open('filename','r') 
temp = f.read() 
f.close() 

f = open('filename', 'w') 
f.write("#testfirstline") 

f.write(temp) 
f.close() 

¿No hay una manera más fácil? Además, veo este ejemplo de dos controles con más frecuencia que abrir un único identificador para leer y escribir ('r +'): ¿por qué?

+0

(Vale la pena señalar: probablemente sea mejor que lea el archivo línea por línea y escriba en un archivo temporal. Cuando haya terminado, elimine el archivo original y reemplácelo por la temperatura) – cwallenpoole

Respuesta

67

Python hace que una gran cantidad de cosas fácil y contiene las bibliotecas y envoltorios para muchas operaciones comunes, pero el objetivo es no ocultar verdades fundamentales.

La verdad fundamental que se encuentra aquí es que, por lo general, no se pueden anteponer datos a una estructura plana existente sin reescribir toda la estructura. Esto es cierto independientemente del idioma.

Existen formas de guardar un identificador de archivo o hacer que su código sea menos legible, muchas de las cuales se proporcionan en otras respuestas, pero ninguna cambia la operación fundamental: debe leer el archivo existente y luego escribir los datos que desea preceder, seguido de los datos existentes que ha leído.

Por supuesto, guárdese el identificador de archivo, pero no intente empaquetar esta operación en el menor número posible de líneas de código. De hecho, nunca busque la menor cantidad de líneas de código, eso es ofuscación, no programación.

+17

"nunca busque las pocas líneas de código - eso es ofuscación, no programación "- Ocultar la cantidad de tiempo que lleva realizar una función no es ofuscación, es abstracción. Si el propósito del código era tomar una cantidad proporcional de tiempo para leer y ejecutar, el código tendría una estructura completamente diferente de lo que realmente es. – Aviendha

3

Puede guardar una llamada de escritura con esto:

f.write('#testfirstline\n' + temp) 

Al utilizar 'r +', que tendría que rebobinar el archivo y después de leer antes de escribir.

+2

+1, aunque podría haber guardado una línea completa de código haciendo 'f.write ('# testfirstline \ n' + temp)' – mtrw

+0

Tienes razón, editaré la respuesta para cambiar eso. – infrared

+3

Recomendaría 'f.writelines (('# testfirstline \ n', tmp))'. Entonces, si la temperatura es enorme, no estás creando otra secuencia enorme para escribir todo esto. O simplemente use la línea de escritura adicional como en el OP ... –

0

Una posibilidad es la siguiente:

import os 
open('tempfile', 'w').write('#testfirstline\n' + open('filename', 'r').read()) 
os.rename('tempfile', 'filename') 
+2

Esto no es seguro en POSIX (condiciones de carrera en algunos sistemas de archivos, creo que XFS). Uno necesita llamar a f.flush() y os.fsync (f.fileno()) en el archivo temporal antes del cambio de nombre. –

+0

@Rosh: No, no lo es. –

+2

http://thunk.org/tytso/blog/2009/03/12/delayed-allocation-and-the-zero-length-file-problem/ –

16

Otro enfoque:

with open("infile") as f1: 
    with open("outfile", "w") as f2: 
     f2.write("#test firstline") 
     for line in f1: 
      f2.write(line) 

o un chiste:

open("outfile", "w").write("#test firstline\n" + open("infile").read()) 

Gracias por la oportunidad de pensar en este problema :)

Saludos

7
with open("file", "r+") as f: s = f.read(); f.seek(0); f.write("prepend\n" + s) 
33

me gustaría seguir con las lecturas y escrituras por separado, pero ciertamente puedo expresar cada uno de manera más concisa:

python2:

with file('filename', 'r') as original: data = original.read() 
with file('filename', 'w') as modified: modified.write("new first line\n" + data) 

python3: Nota

with open('filename', 'r') as original: data = original.read() 
with open('filename', 'w') as modified: modified.write("new first line\n" + data) 

: función de archivo() no está disponible en python3.

+1

Tenga en cuenta que la función 'file()' no está disponible en Python 3, solo en la Versión 2. Simplemente reemplácela por 'open()' en Python 3. – mozzbozz

+3

En realidad, no debe usar la función de archivo en Python 2 , ya sea. Siempre debe abrir archivos usando la función 'open()' en Python. La función de archivo solo está ahí por razones históricas. –

+0

@HenrySchreiner en ese momento, sentí que 'archivo' era más intuitivo, independientemente del consenso de la comunidad y las pautas de estilo comunes. Pero cuando apareció 3.x (y yo era un adoptante bastante entusiasta de FWIW) ya no tuve más opción :) –

2

Esto hace el trabajo sin tener que leer todo el archivo en la memoria, aunque puede que no funcione en Windows

def prepend_line(path, line): 
    with open(path, 'r') as old: 
     os.unlink(path) 
     with open(path, 'w') as new: 
      new.write(str(line) + "\n") 
      shutil.copyfileobj(old, new) 
+0

Me gusta esto, aunque hay que tener cuidado ya que provocará la pérdida de datos si se interrumpe. – Sunday

+0

Haciendo esto sobrescribirá el archivo. ¿Es posible crear un nuevo archivo usando 'shutil.copyfileobj' en lugar de sobrescribir? – alvas

+1

Lo siento @alvas No entiendo muy bien a qué te refieres. Si desea escribir en un nuevo archivo, simplemente coloque una 'ruta' diferente en la segunda llamada a' abrir'. – eug

2

He aquí un revestimiento 3 que creo que es claro y flexible. Utiliza la función list.insert, por lo que si realmente quieres anteponer al archivo usa l.insert (0, 'insert_str'). Cuando hice esto para un Módulo de Python que estoy desarrollando, utilicé l.insert (1, 'insert_str') porque quería omitir la cadena '# - - codificación: utf-8 - -' en la línea 0. Aquí está el código.

f = open(file_path, 'r'); s = f.read(); f.close() 
l = s.splitlines(); l.insert(0, 'insert_str'); s = '\n'.join(l) 
f = open(file_path, 'w'); f.write(s); f.close() 
+0

Podrías convertirlo en un 1-liner también – shadi

0

Si desea anteponer en el archivo después de un texto específico, puede utilizar la siguiente función.

def prepend_text(file, text, after=None): 
    ''' Prepend file with given raw text ''' 
    f_read = open(file, 'r') 
    buff = f_read.read() 
    f_read.close() 
    f_write = open(file, 'w') 
    inject_pos = 0 
    if after: 
     pattern = after 
     inject_pos = buff.find(pattern)+len(pattern) 
    f_write.write(buff[:inject_pos] + text + buff[inject_pos:]) 
    f_write.close() 

Primero, abra el archivo, léelo y guárdelo todo en una sola cadena. Luego tratamos de encontrar el número de personaje en la cadena donde se realizará la inyección. Luego, con una sola escritura y una indexación inteligente de la cadena, podemos reescribir todo el archivo, incluido el texto inyectado ahora.

Cuestiones relacionadas