Замінити та замінити замість додавання


97

У мене є такий код:

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

де я хотів би замінити старий вміст, що міститься у файлі, новим. Однак, коли я виконую свій код, додається файл "test.xml", тобто у мене є старий вміст, замінений новим "заміненим" вмістом. Що я можу зробити, щоб видалити старі речі, а зберегти лише нові?



Коли ви говорите "замінити старий вміст, що міститься у файлі, новим" , вам потрібно прочитати та перетворити поточний вміст data = file.read(). Ви не маєте на увазі "наосліп перезаписати його без необхідності читати спочатку".
smci

Відповіді:


106

Вам потрібно seekпочати файл перед написанням, а потім використати, file.truncate()якщо ви хочете замінити замість:

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

Інший спосіб - прочитати файл, а потім знову відкрити його за допомогою 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))

Ні, truncateані open(..., 'w')не змінить номер inode файлу (я двічі тестував, один раз на Ubuntu 12.04 NFS і один раз на ext4).

До речі, це насправді не пов'язано з Python. Інтерпретатор викликає відповідний API низького рівня. Метод truncate()працює однаково в мові програмування C: Див. Http://man7.org/linux/man-pages/man2/truncate.2.html


Neither truncate nor open(..., 'w') will change the inode number of the fileчому це важливо?
rok

@rok, якщо inode змінюється чи ні, у більшості випадків не є актуальним. Тільки у крайніх випадках, коли ви використовуєте жорсткі посилання, але я раджу уникати жорстких посилань .
guettli

67
file='path/test.xml' 
with open(file, 'w') as filetowrite:
    filetowrite.write('new content')

Відкрийте файл у режимі 'w', і ви зможете замінити його поточний текст, збереживши файл новим вмістом.


5
Це хороший спосіб очистити файл і написати до нього щось нове, але питання полягало в читанні файлу, зміні вмісту та перезаписі оригіналу новим вмістом.
Борис

15

Використовуючи truncate(), рішення може бути

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

1
seek і truncate !!! Я не міг зрозуміти, чому seekодин не працює.
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

У мене була подібна проблема, і замість того, щоб перезаписати мій існуючий файл, використовуючи різні «режими», я просто видалив файл перед його повторним використанням, так що було б так, ніби я додавав новий файл при кожному запуску мого коду .



0

Використання бібліотеки python3 pathlib :

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

Подібний метод із використанням іншого підходу до резервних копій:

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))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.