추가하는 대신 바꾸기 및 덮어 쓰기


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

답변:


113

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

파일 의 inode 번호 truncateopen(..., 'w')변경 하지도 않습니다 (우분투 12.04 NFS로 한 번, ext4로 한 번 테스트).

그건 그렇고, 이것은 실제로 파이썬과 관련이 없습니다. 인터프리터는 해당하는 저수준 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가 변경되거나 대부분의 경우 관련이없는 경우 @rok. 하드 링크를 사용하는 경우에만 하드 링크를 사용하지 않는 것이 좋습니다.
guettli

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

'w'모드에서 파일을 열면 현재 텍스트를 바꾸고 파일을 새 내용으로 저장할 수 있습니다.


6
이것은 파일을 지우고 새로운 내용을 작성하는 좋은 방법이지만 파일을 읽고 내용을 수정하고 원본을 새 내용으로 덮어 쓰는 것이 문제였습니다.
보리스

1
@Boris, 먼저 파일을 읽고이 답변의 코드를 사용하는 데 문제가 있습니까?
Rayhunter

@Rayhunter : 그것은 비효율적
SERV-INC

간단하고 효율적이며 완벽한 방식으로 작업을 수행합니다.
Chikku 야곱

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 2010 년

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

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

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.