ChatGPT解决这个技术问题 Extra ChatGPT

替换和覆盖而不是追加

我有以下代码:

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()。您的意思不是“无需先阅读就盲目地覆盖它”。

B
Boris Verkhovskiy

在写入之前您需要 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))

truncateopen(..., '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 如果 inode 更改与否在大多数情况下不相关。仅在使用硬链接的极端情况下,但 I advice to avoid hard links
与“with open(...)”方法相比,使用“f.seek() ...”方法是否有缺点?
M
Moshe Rabaev
file='path/test.xml' 
with open(file, 'w') as filetowrite:
    filetowrite.write('new content')

以“w”模式打开文件,您将能够用新内容替换其当前文本保存文件。


这是清除文件并向其写入新内容的好方法,但问题是关于读取文件、修改内容并用新内容覆盖原始文件。
@Boris,先读取文件然后使用此答案中的代码有什么问题?
@Rayhunter:效率低下
它简单高效,以完美的方式完成工作。
C
Community

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

seek truncate!!!我无法弄清楚为什么单独使用 seek 不起作用。
@conner.xyz 也许我错了,但 seek 负责改变 cursor 的位置。 write 负责从 cursor 位置写入文件。 write 不关心写入文件后是否有任何内容。 truncate 在此处执行从文件的 光标 位置删除其余内容的工作。
@Almabud,我刚刚测试了 with open(...) as f: f.truncate() f.write(...)(没有 seek(0)),它似乎确实替换了文件内容。
@conner.xyz 最近我正在尝试您的解决方案,因为它更简单,但没有按预期工作。 ` 文件 = <byte_image> pyexiv_img = pyexiv2.ImageData(file.read()) pyexiv_img.clear_exif() file.truncate() file.write(pyexiv_img.get_bytes()) `这不起作用。之后我需要添加 file.seek(0) 才能正常工作。
7
7beggars_nnnnm

See from How to Replace String in File 以一种简单的方式工作,并且是一个适用于 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()

N
Nadia Salgado
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

我有一个类似的问题,而不是使用不同的“模式”覆盖我现有的文件,我只是在再次使用它之前删除了该文件,这样就好像我在每次运行我的代码时都附加到一个新文件.


r
rok

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