Thay thế và ghi đè thay vì thêm vào


97

Tôi có mã sau:

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

nơi tôi muốn thay thế nội dung cũ có trong tệp bằng nội dung mới. Tuy nhiên, khi tôi thực thi mã của mình, tệp "test.xml" được nối thêm vào, tức là tôi có nội dung cũ bị nội dung "thay thế" mới. Tôi có thể làm gì để xóa nội dung cũ và chỉ giữ lại nội dung mới?



Khi bạn nói "thay thế nội dung cũ trong tệp bằng nội dung mới" , bạn cần phải đọc và chuyển đổi nội dung hiện tại data = file.read(). Ý bạn không phải là "ghi đè lên một cách mù quáng mà không cần đọc trước".
smci

Câu trả lời:


106

Bạn cần seekđến đầu tệp trước khi viết và sau đó sử dụng file.truncate()nếu bạn muốn thực hiện thay thế tại chỗ:

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

Cách khác là đọc tệp sau đó mở lại bằng 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))

Cả truncatecũng open(..., 'w')sẽ thay đổi inode số của tập tin (Tôi đã thử nghiệm hai lần, một lần với Ubuntu 12.04 NFS và một lần với ext4).

Nhân tiện, điều này không thực sự liên quan đến Python. Trình thông dịch gọi API cấp thấp tương ứng. Phương thức truncate()hoạt động tương tự trong ngôn ngữ lập trình C: Xem http://man7.org/linux/man-pages/man2/truncate.2.html


Neither truncate nor open(..., 'w') will change the inode number of the filetại sao nó lại quan trọng?
rok

@rok nếu inode thay đổi hay không thì không liên quan trong hầu hết các trường hợp. Chỉ trong những trường hợp phức tạp mà bạn sử dụng liên kết cứng, nhưng tôi khuyên bạn nên tránh liên kết cứng .
guettli

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

Mở tệp ở chế độ 'w', bạn sẽ có thể thay thế văn bản hiện tại của nó, lưu tệp bằng nội dung mới.


5
Đây là một cách tốt để xóa một tệp và viết một cái gì đó mới vào nó, nhưng câu hỏi là về việc đọc tệp, sửa đổi nội dung và ghi đè tệp gốc bằng nội dung mới.
Boris

15

Sử dụng truncate(), giải pháp có thể là

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 !!! Tôi không thể hiểu tại sao seekmột mình lại không hoạt động.
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

Tôi đã gặp sự cố tương tự và thay vì ghi đè tệp hiện có của mình bằng các 'chế độ' khác nhau, tôi chỉ xóa tệp trước khi sử dụng lại, để nó giống như thể tôi đang thêm một tệp mới vào mỗi lần chạy mã của mình .


1

Xem từ Cách thay thế chuỗi trong tệp hoạt động theo cách đơn giản và là câu trả lời phù hợp vớireplace

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

Sử dụng thư viện pathlib của 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))

Phương pháp tương tự sử dụng cách tiếp cận khác nhau để sao lưu:

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))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.