Lesen und überschreiben Sie eine Datei in Python

108

Derzeit verwende ich Folgendes:

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

Das Problem ist jedoch, dass die alte Datei größer als die neue Datei ist. Am Ende habe ich eine neue Datei, die am Ende einen Teil der alten Datei enthält.

compie
quelle

Antworten:

178

Wenn Sie die Datei nicht schließen und erneut öffnen möchten, um Rennbedingungen zu vermeiden, können Sie Folgendes tun truncate:

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

Die Funktionalität wird wahrscheinlich auch sauberer und sicherer sein , openwenn sie als Kontextmanager verwendet wird, der den Dateihandler schließt, selbst wenn ein Fehler auftritt!

with open(filename, 'r+') as f:
    text = f.read()
    text = re.sub('foobar', 'bar', text)
    f.seek(0)
    f.write(text)
    f.truncate()
nosklo
quelle
Nur um mir klar zu sein - sollte dein zweiter Clip haben f.write(text) nach f.truncate()?
Volvox
2
@volvox f.write(text)steht f.truncate()in diesem Code vor; es schreibt den textersten, also nachdem .write()der Dateicursor am Ende von positioniert ist text. Wenn Sie mit dem Abschneiden der Datei fortfahren, werden alle verbleibenden Bytes entfernt, die die Datei nach diesem Zeitpunkt möglicherweise hat. In diesem Fall ist das Endergebnis dasselbe, als ob Sie es vor dem Schreiben abgeschnitten hätten.
Nosklo
Bei sehr großen Dateien kann das Einlesen des gesamten Dateiinhalts in den Speicher unhandlich werden. Daher kann das fileinputModul zur bevorzugten Methode werden. Nach der Übergabe inplace=1wird die Datei zuerst an einen temporären Speicherort verschoben und dann eine neue Datei in den alten Dateinamenpfad geschrieben. Dieser Verschiebungsvorgang ist auf Unix-Dateisystemen schnell, da nur das Dateisystem verschoben wirdinode und nicht der gesamte Inhalt . Anschließend können Sie jede Zeile einzeln lesen und verarbeiten, um ein Aufblähen des Speichers zu vermeiden. :-)
TrinitronX
16

Wahrscheinlich wäre es einfacher und übersichtlicher, die Datei danach zu schließen text = re.sub('foobar', 'bar', text), sie zum Schreiben erneut zu öffnen (wodurch alte Inhalte gelöscht werden ) und Ihren aktualisierten Text darauf zu schreiben.

Il-Bhima
quelle
16

Das fileinputModul verfügt über einen inlineModus zum Schreiben von Änderungen an der Datei, die Sie verarbeiten, ohne temporäre Dateien usw. zu verwenden. Zeilennummer usw., wenn Sie sie innerhalb der Schleife überprüfen möchten.

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

Ehrlich gesagt können Sie sich diese Klasse ansehen, die ich erstellt habe und die grundlegende Dateioperationen ausführt. Die Schreibmethode überschreibt und hängt alte Daten.

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
quelle
-2

Versuchen Sie es in eine neue Datei zu schreiben.

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
quelle