Ganti dan timpa alih-alih menambahkan

96

Saya memiliki kode berikut:

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()

di mana saya ingin mengganti konten lama yang ada di dalam file dengan konten baru. Namun, ketika saya menjalankan kode saya, file "test.xml" ditambahkan, yaitu saya memiliki konten lama yang diikuti oleh konten baru yang "diganti". Apa yang dapat saya lakukan untuk menghapus yang lama dan hanya menyimpan yang baru?

Kaly
sumber
Saat Anda mengatakan "ganti konten lama yang ada di file dengan konten baru" , Anda perlu membaca dan mengubah konten saat ini data = file.read(). Anda tidak bermaksud "menimpanya secara membabi buta tanpa perlu membacanya terlebih dahulu".
smci

Jawaban:

105

Anda harus seekmemulai file sebelum menulis dan kemudian menggunakan file.truncate()jika Anda ingin melakukan ganti:

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()

Cara lainnya adalah dengan membaca file kemudian membukanya kembali dengan 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))

Tidak truncatejuga open(..., 'w')akan mengubah nomor inode file (saya menguji dua kali, sekali dengan Ubuntu 12.04 NFS dan sekali dengan ext4).

Ngomong-ngomong, ini tidak benar-benar terkait dengan Python. Penerjemah memanggil API tingkat rendah yang sesuai. Metode truncate()kerjanya sama dalam bahasa pemrograman C: Lihat http://man7.org/linux/man-pages/man2/truncate.2.html

guettli
sumber
Neither truncate nor open(..., 'w') will change the inode number of the filemengapa ini penting?
rok
@rok jika inode berubah atau tidak tidak relevan dalam banyak kasus. Hanya dalam kasus edge di mana Anda menggunakan hard-link, tapi saya menyarankan untuk menghindari hard link .
guettli
67
file='path/test.xml' 
with open(file, 'w') as filetowrite:
    filetowrite.write('new content')

Buka file dalam mode 'w', Anda akan dapat mengganti teksnya saat ini, simpan file dengan konten baru.

Chikku Jacob
sumber
5
Ini adalah cara yang baik untuk menghapus file dan menulis sesuatu yang baru, tetapi pertanyaannya adalah tentang membaca file, mengubah konten, dan menimpa file asli dengan konten baru.
Boris
15

Menggunakan truncate(), solusinya bisa jadi

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
sumber
1
seek dan truncate !!! Saya tidak tahu mengapa seeksendirian tidak berhasil.
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

Saya memiliki masalah yang sama, dan alih-alih menimpa file saya yang sudah ada menggunakan 'mode' yang berbeda, saya hanya menghapus file sebelum menggunakannya lagi, sehingga seolah-olah saya sedang menambahkan file baru pada setiap menjalankan kode saya .

Nadia Salgado
sumber
1

Lihat dari Cara Mengganti String di File bekerja dengan cara yang sederhana dan merupakan jawaban yang sesuaireplace

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
sumber
0

Menggunakan pustaka pathlib python3 :

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))

Metode serupa menggunakan pendekatan berbeda untuk pencadangan:

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
sumber