追加する代わりに置き換えて上書きする


102

私は次のコードを持っています:

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 2018年

回答:


112

あなたは必要な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()

もう1つの方法は、ファイルを読み取ってから、次のコマンドで再度開くことです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))

ファイルのiノード番号truncateopen(..., 'w')変更されません(Ubuntu 12.04 NFSで1回、ext4で1回、計2回テストしました)。

ちなみに、これは実際には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どうしてそれが重要ですか?
韓国

ほとんどの場合、iノードが変更されるかどうかは関係ありません。ハードリンクを使用するエッジケースのみですが、ハードリンクを避けることをお勧めします
guettli

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

'w'モードでファイルを開くと、ファイルを保存している現在のテキストを新しいコンテンツに置き換えることができます。


6
これは、ファイルをクリアして新しいものを書き込むための良い方法ですが、問題は、ファイルを読み取り、内容を変更し、元の内容を新しい内容で上書きすることでした。
ボリス

1
@Boris、最初にファイルを読み取ってから、この回答のコードを使用する場合の問題は何ですか?
レイハンター

@Rayhunter:それは非効率的だ
SERV-INC

それはシンプルで効率的で、完璧な方法で仕事をします。
ChikkuJacob20年

16

を使用する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))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.