Przeczytaj i nadpisz plik w Pythonie

108

Obecnie używam tego:

f = open(filename, 'r+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.write(text)
f.close()

Problem polega jednak na tym, że stary plik jest większy niż nowy. W rezultacie otrzymuję nowy plik, który ma na końcu część starego pliku.

compie
źródło

Odpowiedzi:

178

Jeśli nie chcesz zamykać i ponownie otwierać pliku, aby uniknąć warunków wyścigu, możesz truncate:

f = open(filename, 'r+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.write(text)
f.truncate()
f.close()

Funkcjonalność prawdopodobnie będzie również czystsza i bezpieczniejsza,open gdy będzie używana jako menedżer kontekstu, co zamknie program obsługi plików, nawet jeśli wystąpi błąd!

with open(filename, 'r+') as f:
    text = f.read()
    text = re.sub('foobar', 'bar', text)
    f.seek(0)
    f.write(text)
    f.truncate()
nosklo
źródło
Żeby było jasne - czy twój drugi klip powinien mieć f.write(text)później f.truncate()?
volvox
2
@volvox f.write(text)jest przed f.truncate()w tym kodzie; zapisuje textpierwszy, więc po .write()umieszczeniu kursora pliku na końcu text. Kontynuowanie obcięcia pliku spowoduje usunięcie wszelkich pozostałych bajtów, które plik może mieć po tym momencie. W takim przypadku wynik końcowy byłby taki sam, jak w przypadku obcięcia przed zapisaniem.
nosklo
W przypadku bardzo dużych plików wczytywanie całej zawartości pliku do pamięci może stać się nieporęczne. Dlatego fileinputmoduł może stać się metodą preferowaną. Po przekazaniu inplace=1najpierw przeniesie plik do tymczasowej lokalizacji, a następnie zapisze nowy plik w starej ścieżce do pliku. Ta operacja przenoszenia jest szybka na unixowych systemach plików, ponieważ przenosi tylko system plików inode, a nie całą zawartość. Następnie możesz czytać i przetwarzać każdą linię osobno, aby uniknąć nadmiaru pamięci. :-)
TrinitronX
16

Prawdopodobnie byłoby łatwiej i schludniej zamknąć plik później text = re.sub('foobar', 'bar', text), ponownie otworzyć go do zapisu (usuwając w ten sposób starą zawartość) i zapisać w nim zaktualizowany tekst.

Il-Bhima
źródło
16

fileinputModuł posiada inlinetryb pisania zmiany w pliku jesteś przetwarzania bez użycia plików tymczasowych itd. Moduł ładnie obudowuje wspólne działanie pętli na liniach w liście plików za pośrednictwem obiektu, który przejrzyście śledzi nazwy pliku, numer linii itp., jeśli chcesz sprawdzić je wewnątrz pętli.

import fileinput
for line in fileinput.FileInput("file",inplace=1):
    if "foobar" in line:
         line=line.replace("foobar","bar")
    print line
ghostdog74
źródło
0

Szczerze, możesz rzucić okiem na tę klasę, którą zbudowałem, która wykonuje podstawowe operacje na plikach. Metoda write zastępuje i dołącza stare dane.

class IO:
    def read(self, filename):
        toRead = open(filename, "rb")

        out = toRead.read()
        toRead.close()
        
        return out
    
    def write(self, filename, data):
        toWrite = open(filename, "wb")

        out = toWrite.write(data)
        toWrite.close()

    def append(self, filename, data):
        append = self.read(filename)
        self.write(filename, append+data)
        
CodinGuy
źródło
-2

Spróbuj zapisać go w nowym pliku ...

f = open(filename, 'r+')
f2= open(filename2,'a+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.close()
f2.write(text)
fw.close()
sk7979
źródło