Ersetzen und überschreiben statt anhängen

101

Ich habe folgenden Code:

import re
#open the xml file for reading:
file = open('path/test.xml','r+')
#convert to string:
data = file.read()
file.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>",data))
file.close()

Hier möchte ich den alten Inhalt in der Datei durch den neuen Inhalt ersetzen. Wenn ich jedoch meinen Code ausführe, wird die Datei "test.xml" angehängt, dh ich habe den alten Inhalt gefolgt vom neuen "ersetzten" Inhalt. Was kann ich tun, um das alte Zeug zu löschen und nur das neue zu behalten?

Kaly
quelle
Wenn Sie "Ersetzen Sie den alten Inhalt in der Datei durch den neuen Inhalt" sagen , müssen Sie den aktuellen Inhalt einlesen und transformieren data = file.read(). Sie meinen nicht "blind überschreiben, ohne es zuerst lesen zu müssen".
smci

Antworten:

112

Sie müssen seekvor dem Schreiben an den Anfang der Datei gehen und diese dann verwenden, file.truncate()wenn Sie Folgendes ersetzen möchten:

import re

myfile = "path/test.xml"

with open(myfile, "r+") as f:
    data = f.read()
    f.seek(0)
    f.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>", r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", data))
    f.truncate()

Die andere Möglichkeit besteht darin, die Datei zu lesen und sie dann erneut zu öffnen mit open(myfile, 'w'):

with open(myfile, "r") as f:
    data = f.read()

with open(myfile, "w") as f:
    f.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>", r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", data))

Weder truncatenoch open(..., 'w')wird die Inode- Nummer der Datei geändert (ich habe zweimal getestet, einmal mit Ubuntu 12.04 NFS und einmal mit ext4).

Dies hängt übrigens nicht wirklich mit Python zusammen. Der Interpreter ruft die entsprechende Low-Level-API auf. Die Methode truncate()funktioniert in der Programmiersprache C genauso: Siehe http://man7.org/linux/man-pages/man2/truncate.2.html

guettli
quelle
Neither truncate nor open(..., 'w') will change the inode number of the filewarum ist es wichtig
Rok
@rok ob sich der Inode ändert oder nicht, ist in den meisten Fällen nicht relevant. Nur in Randfällen, in denen Sie Hardlinks verwenden, aber ich rate, Hardlinks zu vermeiden .
Guettli
71
file='path/test.xml' 
with open(file, 'w') as filetowrite:
    filetowrite.write('new content')

Öffnen Sie die Datei im 'w'-Modus. Sie können den aktuellen Text ersetzen und die Datei durch neuen Inhalt speichern.

Chikku Jacob
quelle
6
Dies ist eine gute Möglichkeit, eine Datei zu löschen und etwas Neues zu schreiben. Es ging jedoch darum, die Datei zu lesen, den Inhalt zu ändern und das Original mit dem neuen Inhalt zu überschreiben.
Boris
1
@Boris, was ist das Problem, wenn Sie zuerst die Datei lesen und dann den Code in dieser Antwort verwenden?
Rayhunter
@ Rayhunter: Es ist ineffizient
serv-inc
Es ist einfach und effizient und erledigt die Arbeit perfekt.
Chikku Jacob
16

Mit truncate()könnte die Lösung sein

import re
#open the xml file for reading:
with open('path/test.xml','r+') as f:
    #convert to string:
    data = f.read()
    f.seek(0)
    f.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>",data))
    f.truncate()
serv-inc
quelle
1
seek und truncate !!! Ich konnte nicht herausfinden, warum seekallein nicht funktionierte.
conner.xyz
2
import os#must import this library
if os.path.exists('TwitterDB.csv'):
        os.remove('TwitterDB.csv') #this deletes the file
else:
        print("The file does not exist")#add this to prevent errors

Ich hatte ein ähnliches Problem und anstatt meine vorhandene Datei mit den verschiedenen "Modi" zu überschreiben, habe ich die Datei einfach gelöscht, bevor ich sie erneut verwendete, so dass es so war, als würde ich bei jedem Durchlauf meines Codes an eine neue Datei anhängen .

Nadia Salgado
quelle
1

Siehe Ersetzen von Zeichenfolgen in Dateien funktioniert auf einfache Weise und ist eine Antwort, die funktioniertreplace

fin = open("data.txt", "rt")
fout = open("out.txt", "wt")

for line in fin:
    fout.write(line.replace('pyton', 'python'))

fin.close()
fout.close()
Yaacov NNNNM
quelle
0

Verwenden der Python3- Pathlib- Bibliothek:

import re
from pathlib import Path
import shutil

shutil.copy2("/tmp/test.xml", "/tmp/test.xml.bak") # create backup
filepath = Path("/tmp/test.xml")
content = filepath.read_text()
filepath.write_text(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", content))

Ähnliche Methode mit unterschiedlichem Ansatz für Backups:

from pathlib import Path

filepath = Path("/tmp/test.xml")
filepath.rename(filepath.with_suffix('.bak')) # different approach to backups
content = filepath.read_text()
filepath.write_text(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", content))
rok
quelle