Leer y sobrescribir un archivo en Python

108

Actualmente estoy usando esto:

f = open(filename, 'r+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.write(text)
f.close()

Pero el problema es que el archivo antiguo es más grande que el nuevo. Así que termino con un archivo nuevo que tiene una parte del archivo anterior al final.

compie
fuente

Respuestas:

178

Si no desea cerrar y volver a abrir el archivo, para evitar condiciones de carrera, puede truncate:

f = open(filename, 'r+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.write(text)
f.truncate()
f.close()

Es probable que la funcionalidad también sea más limpia y segura si se usa opencomo administrador de contexto, lo que cerrará el administrador de archivos, incluso si se produce un error.

with open(filename, 'r+') as f:
    text = f.read()
    text = re.sub('foobar', 'bar', text)
    f.seek(0)
    f.write(text)
    f.truncate()
nosklo
fuente
Para que quede claro en mi mente, ¿debería tener un segundo clip f.write(text)después f.truncate()?
Volvox
2
@volvox f.write(text)está antes f.truncate()en este código; escribe el textprimero, por lo que después de que .write()el cursor del archivo se coloca al final de text. Proceder a truncar el archivo eliminará los bytes restantes que pueda tener el archivo después de este punto. En este caso, el resultado final sería el mismo que si trunca antes de escribir.
nosklo
Para archivos muy grandes, leer todo el contenido del archivo en la memoria puede resultar difícil de manejar. Por tanto, el fileinputmódulo puede convertirse en el método preferido. Cuando se pasa inplace=1, primero moverá el archivo a una ubicación temporal y luego escribirá un nuevo archivo en la ruta del nombre de archivo anterior. Esta operación de movimiento es rápida en sistemas de archivos Unix, porque solo mueve el sistema de archivos inode, no el contenido completo. Luego, puede leer y procesar cada línea individualmente para evitar la sobrecarga de la memoria. :-)
TrinitronX
16

Probablemente sería más fácil y ordenado cerrar el archivo después text = re.sub('foobar', 'bar', text), volver a abrirlo para escribir (borrando así el contenido antiguo) y escribir el texto actualizado en él.

Il-Bhima
fuente
16

El fileinputmódulo tiene un inlinemodo para escribir cambios en el archivo que está procesando sin usar archivos temporales, etc. El módulo encapsula muy bien la operación común de recorrer las líneas en una lista de archivos, a través de un objeto que realiza un seguimiento transparente del nombre del archivo, número de línea, etc. si desea inspeccionarlos dentro del bucle.

import fileinput
for line in fileinput.FileInput("file",inplace=1):
    if "foobar" in line:
         line=line.replace("foobar","bar")
    print line
ghostdog74
fuente
0

Honestamente, puedes echar un vistazo a esta clase que construí y que realiza operaciones básicas de archivos. El método de escritura sobrescribe y anexa mantiene los datos antiguos.

class IO:
    def read(self, filename):
        toRead = open(filename, "rb")

        out = toRead.read()
        toRead.close()
        
        return out
    
    def write(self, filename, data):
        toWrite = open(filename, "wb")

        out = toWrite.write(data)
        toWrite.close()

    def append(self, filename, data):
        append = self.read(filename)
        self.write(filename, append+data)
        
CodinGuy
fuente
-2

Intente escribirlo en un archivo nuevo.

f = open(filename, 'r+')
f2= open(filename2,'a+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.close()
f2.write(text)
fw.close()
sk7979
fuente