แทนที่และเขียนทับแทนการต่อท้าย


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" จะถูกต่อท้ายนั่นคือฉันมีเนื้อหาเก่าที่มาจากเนื้อหา "แทนที่" ใหม่ ฉันจะทำอย่างไรเพื่อลบสิ่งเก่าและเก็บใหม่เท่านั้น



เมื่อคุณพูด"แทนที่เนื้อหาเก่าที่อยู่ในแฟ้มที่มีเนื้อหาใหม่"data = file.read()คุณจะต้องอ่านและแปลงเนื้อหาปัจจุบัน คุณไม่ได้หมายความว่า "เขียนทับแบบสุ่มสี่สุ่มห้าโดยไม่จำเป็นต้องอ่านก่อน"
smci

คำตอบ:


105

คุณต้องseekไปที่จุดเริ่มต้นของไฟล์ก่อนที่จะเขียนจากนั้นใช้file.truncate()หากคุณต้องการทำการแทนที่ inplace:

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จำนวนแฟ้ม (ผมทดสอบสองครั้งครั้งกับอูบุนตู 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 หากไอโหนดเปลี่ยนแปลงหรือไม่ไม่เกี่ยวข้องในกรณีส่วนใหญ่ เฉพาะในกรณีขอบที่คุณใช้การเชื่อมโยงยาก แต่คำแนะนำฉันจะหลีกเลี่ยงการเชื่อมโยงอย่างหนัก
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 library:

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))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.