@Ani drugi post jest i tak duplikatem Wstawiania linii w określonym miejscu w pliku tekstowym i na pewno są tutaj jasne, skomponowane odpowiedzi. Dlaczego nie dodać odpowiedzi tutaj zamiast w inny sposób? Przyjęta odpowiedź nie jest warunkiem dobrego pytania.
Bhargav Rao
@BhargavRao Głosowanie wycofane. Powinienem był znaleźć ten duplikat!
Ani Menon
Odpowiedzi:
134
Niestety nie ma możliwości wstawienia do środka pliku bez ponownego zapisania. Jak wskazywały poprzednie plakaty, możesz dołączyć do pliku lub nadpisać jego część za pomocą wyszukiwania, ale jeśli chcesz dodać rzeczy na początku lub w środku, musisz go przepisać.
To kwestia systemu operacyjnego, a nie Pythona. Tak samo jest we wszystkich językach.
Zwykle czytam z pliku, wprowadzam modyfikacje i zapisuję je do nowego pliku o nazwie myfile.txt.tmp lub czegoś podobnego. Jest to lepsze niż wczytywanie całego pliku do pamięci, ponieważ plik może być na to za duży. Po utworzeniu pliku tymczasowego zmieniam jego nazwę na taką samą, jak oryginalnego pliku.
Jest to dobry, bezpieczny sposób na zrobienie tego, ponieważ jeśli zapis do pliku ulegnie awarii lub zostanie przerwany z jakiegokolwiek powodu, nadal masz nienaruszony oryginalny plik.
Czy narzędzia unixowe, takie jak awk / sed, robią coś podobnego w swoim kodzie?
Manish Gill
Nie jest prawdą, że jest to takie samo we wszystkich językach. W języku ActionScript: fileStream.openAsync (nazwa pliku, FileMode.UPDATE); Następnie mogę przejść do dowolnego miejsca w pliku i zmienić wszystko.
AndrewBenjamin,
2
@AndrewBenjamin Czy wiesz, jakie wywołania systemowe wykonuje ActionScript? Czy istnieje możliwość, że openAsync czyta plik i zapisuje nowy po wywołaniu?
AlexLordThorsen
@Rawrgulmuffins Nie mam. Wiem jednak, że nie wczytuje on całego pliku do pamięci, ponieważ używałem go do obsługi plików o rozmiarze kilku GB. Podejrzewam, że to to samo, co pisanie za pomocą streamwritera C #. Postrzegam Pythona jako narzędzie do szybkiego robienia małych rzeczy, a nie jako programowanie na dużą skalę i manipulowanie plikami.
AndrewBenjamin
4
@AndrewBenjamin, użytkownik nie pyta o przeszukiwanie pliku i zmienianie go (każdy język, który znam, może to zrobić); pyta o wstawienie tekstu, co różni się od zwykłej zmiany / nadpisania tego, co już jest w pliku. Może w praktycznym zastosowaniu jest inaczej, ale nic, co mogę znaleźć w API ActionScript, nie wskazuje, że zachowuje się on inaczej niż jakikolwiek inny język w tym zakresie.
eestrada
104
Zależy od tego, co chcesz zrobić. Aby dołączyć, możesz otworzyć go za pomocą „a”:
with open("foo.txt","a")as f:
f.write("new line\n")
Jeśli chcesz coś wstępnie przygotować, musisz najpierw przeczytać z pliku:
with open("foo.txt","r+")as f:
old = f.read()# read everything in the file
f.seek(0)# rewind
f.write("new line\n"+ old)# write the new line before
Tylko mały dodatek, aby użyć withinstrukcji w Pythonie 2.5, musisz dodać "z przyszłego importu z_statement". Poza tym otwieranie plików z withinstrukcją jest zdecydowanie bardziej czytelne i mniej podatne na błędy niż zamykanie ręczne.
Alexander Kojevnikov,
2
Możesz rozważyć fileinputbibliotekę pomocniczą, która ładnie obsługuje brudną procedurę otwierania / odczytu / modyfikacji / zapisu / zamiany podczas używania inline=Truearg. Przykład tutaj: stackoverflow.com/a/2363893/47390
mikegreenberg
3
Po prostu nie zapomnij zamknąć pliku. f.Close()
D.Rosado
5
To nie jest styl, którego używam, D.Rosado, ale kiedy używam stylu ze stylem, nie sądzę, abyś musiał ręcznie zamykać. Z śledzi zasoby, które tworzy.
Chris
4
Państwo nie trzeba ręcznie zamknąć pliku. O to właśnie chodzi w używaniu „z” tutaj. (Cóż, w rzeczywistości Python robi to, gdy tylko obiekt pliku jest usuwany z pamięci, co w CPythonie ma miejsce, gdy nazwa związana z nim wychodzi poza zakres ... ale inne implementacje tego nie robią, a CPython może przestać to robić pewnego dnia , więc „z” jest zalecane)
Jürgen A. Erhard
71
fileinputModuł biblioteki standardowej Pythona będzie przepisać inplace pliku, jeśli używasz inplace = 1 parametr:
import sys
import fileinput
# replace all occurrences of 'sit' with 'SIT' and insert a line after the 5thfor i, line in enumerate(fileinput.input('lorem_ipsum.txt', inplace=1)):
sys.stdout.write(line.replace('sit','SIT'))# replace 'sit' and writeif i ==4: sys.stdout.write('\n')# write a blank line after the 5th line
Jak to ma działać w python3? Właśnie przeportowałem aplikację, która miała taki kod z pythona na python3 i po prostu nie mogłem go w ogóle poprawnie uruchomić. Zmienna „line” jest typem bajtów, próbowałem zdekodować ją do Unicode, a następnie zmodyfikować, a następnie zakodować z powrotem do bajtów, ale po prostu nie działałaby dobrze. To wywołało wyjątek, którego nie pamiętam. Czy ludzie używają fileinput inplace = 1 w python3 z jakimś sukcesem?
Ale to żaden problem, ponieważ najpierw przetestowałeś go na nieistotnym pliku, prawda?
Paula Livingstone
33
Przepisanie pliku w miejscu często polega na zapisaniu starej kopii pod zmienioną nazwą. Użytkownicy Uniksa dodają a, ~aby zaznaczyć stary. Ludzie z Windows robią różne rzeczy - dodają .bak lub .old - lub całkowicie zmieniają nazwę pliku lub umieszczają ~ na początku nazwy.
import shutil
shutil.move( afile, afile+"~")
destination= open( aFile,"w")
source= open( aFile+"~","r")for line in source:
destination.write( line )if<some condition>:
destination.write(>some additional line>+"\n")
source.close()
destination.close()
Wygląda dobrze. Zastanawiasz się, czy .readlines () jest lepsze niż iterowanie źródła?
bozdoz,
2
@bozdoz: iteracja jest lepsza, ponieważ readlines czyta cały plik. Nie nadaje się do dużych plików. Oczywiście zakłada to, że możesz dokonywać modyfikacji w tak zlokalizowany sposób. Czasami nie możesz lub Twój kod staje się znacznie bardziej skomplikowany.
Jürgen A. Erhard
@ S.Lott: os.rename(aFile, aFile + "~")zmieni nazwę pliku źródłowego, nie tworząc kopii.
Patapoom
14
Moduł mmap w Pythonie pozwoli ci wstawić do pliku. Poniższy przykład pokazuje, jak można to zrobić w systemie Unix (mmap systemu Windows może być inny). Należy pamiętać, że nie obsługuje to wszystkich błędów i może spowodować uszkodzenie lub utratę oryginalnego pliku. Ponadto nie obsługuje to ciągów znaków Unicode.
import os
from mmap import mmap
def insert(filename, str, pos):if len(str)<1:# nothing to insertreturn
f = open(filename,'r+')
m = mmap(f.fileno(), os.path.getsize(filename))
origSize = m.size()# or this could be an errorif pos > origSize:
pos = origSize
elif pos <0:
pos =0
m.resize(origSize + len(str))
m[pos+len(str):]= m[pos:origSize]
m[pos:pos+len(str)]= str
m.close()
f.close()
Można to również zrobić bez mmap z plikami otwartymi w trybie 'r +', ale jest to mniej wygodne i mniej wydajne, ponieważ musiałbyś czytać i tymczasowo przechowywać zawartość pliku od pozycji wstawienia do EOF - co może być ogromny.
Jak wspomniał Adam, musisz wziąć pod uwagę ograniczenia swojego systemu, zanim będziesz mógł zdecydować, czy masz wystarczająco dużo pamięci, aby wczytać wszystko do pamięci, wymień jej części i ponownie zapisz.
Jeśli masz do czynienia z małym plikiem lub nie masz problemów z pamięcią, może to pomóc:
Opcja 1)
Wczytaj cały plik do pamięci, wykonaj podstawienie wyrażenia regularnego na całej lub części linii i zastąp ją tą linią plus dodatkową linią. Musisz upewnić się, że „środkowa linia” jest unikalna w pliku lub jeśli w każdej linii znajdują się znaczniki czasu, powinno to być całkiem niezawodny.
# open file with r+b (allow write and binary mode)
f = open("file.log",'r+b')# read entire content of file into memory
f_content = f.read()# basically match middle line and replace it with itself and the extra line
f_content = re.sub(r'(middle line)', r'\1\nnew line', f_content)# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)# clear file content
f.truncate()# re-write the content with the updated content
f.write(f_content)# close file
f.close()
Opcja 2)
Znajdź środkową linię i zastąp ją tą linią plus dodatkową linią.
# open file with r+b (allow write and binary mode)
f = open("file.log",'r+b')# get array of lines
f_content = f.readlines()# get middle line
middle_line = len(f_content)/2# overwrite middle line
f_content[middle_line]+="\nnew line"# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)# clear file content
f.truncate()# re-write the content with the updated content
f.write(''.join(f_content))# close file
f.close()
Odpowiedzi:
Niestety nie ma możliwości wstawienia do środka pliku bez ponownego zapisania. Jak wskazywały poprzednie plakaty, możesz dołączyć do pliku lub nadpisać jego część za pomocą wyszukiwania, ale jeśli chcesz dodać rzeczy na początku lub w środku, musisz go przepisać.
To kwestia systemu operacyjnego, a nie Pythona. Tak samo jest we wszystkich językach.
Zwykle czytam z pliku, wprowadzam modyfikacje i zapisuję je do nowego pliku o nazwie myfile.txt.tmp lub czegoś podobnego. Jest to lepsze niż wczytywanie całego pliku do pamięci, ponieważ plik może być na to za duży. Po utworzeniu pliku tymczasowego zmieniam jego nazwę na taką samą, jak oryginalnego pliku.
Jest to dobry, bezpieczny sposób na zrobienie tego, ponieważ jeśli zapis do pliku ulegnie awarii lub zostanie przerwany z jakiegokolwiek powodu, nadal masz nienaruszony oryginalny plik.
źródło
Zależy od tego, co chcesz zrobić. Aby dołączyć, możesz otworzyć go za pomocą „a”:
Jeśli chcesz coś wstępnie przygotować, musisz najpierw przeczytać z pliku:
źródło
with
instrukcji w Pythonie 2.5, musisz dodać "z przyszłego importu z_statement". Poza tym otwieranie plików zwith
instrukcją jest zdecydowanie bardziej czytelne i mniej podatne na błędy niż zamykanie ręczne.fileinput
bibliotekę pomocniczą, która ładnie obsługuje brudną procedurę otwierania / odczytu / modyfikacji / zapisu / zamiany podczas używaniainline=True
arg. Przykład tutaj: stackoverflow.com/a/2363893/47390f.Close()
fileinput
Moduł biblioteki standardowej Pythona będzie przepisać inplace pliku, jeśli używasz inplace = 1 parametr:źródło
Przepisanie pliku w miejscu często polega na zapisaniu starej kopii pod zmienioną nazwą. Użytkownicy Uniksa dodają a,
~
aby zaznaczyć stary. Ludzie z Windows robią różne rzeczy - dodają .bak lub .old - lub całkowicie zmieniają nazwę pliku lub umieszczają ~ na początku nazwy.Zamiast tego
shutil
możesz użyć następujących.źródło
os.rename(aFile, aFile + "~")
zmieni nazwę pliku źródłowego, nie tworząc kopii.Moduł mmap w Pythonie pozwoli ci wstawić do pliku. Poniższy przykład pokazuje, jak można to zrobić w systemie Unix (mmap systemu Windows może być inny). Należy pamiętać, że nie obsługuje to wszystkich błędów i może spowodować uszkodzenie lub utratę oryginalnego pliku. Ponadto nie obsługuje to ciągów znaków Unicode.
Można to również zrobić bez mmap z plikami otwartymi w trybie 'r +', ale jest to mniej wygodne i mniej wydajne, ponieważ musiałbyś czytać i tymczasowo przechowywać zawartość pliku od pozycji wstawienia do EOF - co może być ogromny.
źródło
Jak wspomniał Adam, musisz wziąć pod uwagę ograniczenia swojego systemu, zanim będziesz mógł zdecydować, czy masz wystarczająco dużo pamięci, aby wczytać wszystko do pamięci, wymień jej części i ponownie zapisz.
Jeśli masz do czynienia z małym plikiem lub nie masz problemów z pamięcią, może to pomóc:
Opcja 1) Wczytaj cały plik do pamięci, wykonaj podstawienie wyrażenia regularnego na całej lub części linii i zastąp ją tą linią plus dodatkową linią. Musisz upewnić się, że „środkowa linia” jest unikalna w pliku lub jeśli w każdej linii znajdują się znaczniki czasu, powinno to być całkiem niezawodny.
Opcja 2) Znajdź środkową linię i zastąp ją tą linią plus dodatkową linią.
źródło
Napisałem małą klasę, aby zrobić to porządnie.
Następnie możesz go użyć w ten sposób:
źródło
Jeśli znasz jakiegoś Uniksa, możesz spróbować następujących rzeczy:
Uwagi: $ oznacza wiersz polecenia
Załóżmy, że masz plik my_data.txt z taką zawartością:
Następnie za pomocą
os
modułu możesz użyć zwykłychsed
poleceńJeśli nie jesteś świadomy seda, sprawdź to, jest to niezwykle przydatne.
źródło