Заменить и перезаписать вместо добавления

96

У меня такой код:

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», т.е. у меня есть старый контент, за которым следует новый «замененный» контент. Что я могу сделать, чтобы удалить старые вещи и оставить только новые?

Кали
источник
2
stackoverflow.com/questions/2424000/…
Кемаль Фадиллах
Когда вы говорите «заменить старое содержимое в файле новым содержимым» , вам необходимо прочитать и преобразовать текущее содержимое data = file.read(). Вы не имеете в виду «слепо перезаписать его, не читая сначала».
smci

Ответы:

105

Вам нужно 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, изменяется ли индексный дескриптор или нет, в большинстве случаев не имеет значения. Только в крайних случаях, когда вы используете жесткие ссылки, но я советую избегать жестких ссылок .
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()
serv-inc
источник
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

У меня была аналогичная проблема, и вместо того, чтобы перезаписывать существующий файл с использованием разных `` режимов '', я просто удалил файл перед его повторным использованием, так что это было бы так, как если бы я добавлял новый файл при каждом запуске моего кода. .

Надя Сальгадо
источник
1

См. « Как заменить строку в файле» работает простым способом и является ответом, который работает сreplace

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

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

fin.close()
fout.close()
Яаков ННННМ
источник
0

Использование библиотеки 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))

Аналогичный метод с использованием другого подхода к резервному копированию:

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))
рок
источник