2012-01-05 10 views
11

Potrzebuję zaktualizować plik. Przeczytałem to i zapisałem ze zmianami. Wolę jednak pisać do pliku tymczasowego i zmienić jego nazwę na miejsce.W pythonie, należy utworzyć plik tempfile w tym samym katalogu, co inny plik?

temp = tempfile.NamedTemporaryFile() 
tempname = temp.name 
temp.write(new_data) 
temp.close() 
os.rename(tempname, data_file_name) 

Problemem jest to, że tempfile.NamedTemporaryFile() sprawia plik tymczasowy w /tmp który jest inny system plików. Oznacza to, że nie powiodło się os.rename(). Jeśli użyję zamiast tego shlib.move(), to nie mam aktualizacji atomowej, którą zapewnia "mv" (dla plików w tym samym systemie plików, Yadda, Yadda itp.).

Wiem, że tempfile.NamedTemporaryFile() przyjmuje parametr "dir", ale data_file_name może być "foo.txt", w takim przypadku dir = '.'; lub data_file_name może być "/path/to/the/data/foo.txt", w takim przypadku dir = "/path/to/the/data".

Co naprawdę chciałbym to plik tymczasowy to data_file_name + "kilka losowych danych". Miałoby to tę zaletę, że zawiodło w sposób, który pozostawiłby po sobie przydatne wskazówki.

Sugestie?

+3

Dlaczego w pierwszej kolejności używasz pliku tymczasowego, jeśli nie chcesz, aby został on umieszczony w katalogu plików tymczasowych? Co przemawia przeciwko używaniu zwykłych plików? –

+1

David: Chcę użyć pliku tymczasowego, ponieważ chcę, aby aktualizacja była atomowa (lub atomowa, jak można z os.rename()). Oznacza to, że jeśli system plików zapełni się lub jest jakiś inny problem, nie chcę, aby plik był napisany w połowie. – TomOnTime

+0

Może to być trudne do osiągnięcia, ponieważ nigdy nie wiadomo, czy pliki zapisane w innym folderze znajdują się w tym samym systemie plików, co katalog lokalny. Widzę zaletę organizowania danych wyjściowych w rodzaju zatwierdzenia. Aby być względnie pewnym, że tak jest, prawdopodobnie zarządzałbym własnym katalogiem tymczasowym - chociaż wtedy dbasz również o porządkowanie tego folderu. –

Odpowiedz

17

Można użyć:

  • prefix aby rozpocząć tymczasowy plik o tej samej nazwie co plik oryginalny .
  • dir aby określić, gdzie umieścić plik tymczasowy.
  • os.path.split, aby podzielić katalog z nazwą pliku.

import tempfile 
import os 
dirname, basename = os.path.split(filename) 
temp = tempfile.NamedTemporaryFile(prefix=basename, dir=dirname) 
print(temp.name) 
+0

Jeśli nazwa_pliku = "foo", wtedy dirname będzie "". Jestem mile zaskoczony, że NamedTemporaryFile działa z dir = '' tak samo jak dir = None. Dzięki! – TomOnTime

+0

Aby to wyraźnie powiedzieć: Musisz również przekazać 'delete = False' do konstruktora NamedTemporaryFile, lub plik zostanie usunięty przy zamknięciu. – moeffju

2

używam aktualny czas jako „pewne losowe dane” dołączany do łańcucha bazowej dla unikalnej nazwy pliku tymczasowego:

import time 

temp_file_name = data_file_name + str(time.time()) 
+0

To jest kuszące, ale widziałem wystarczająco dużo problemów z bezpieczeństwem ze strony osób tuszujących swój własny system plików tymczasowych, o których wiem, że używają tego, który zapewnia tempfile. – TomOnTime

+0

Tak jak dodana uwaga tutaj, kilka lat później, będzie to powodować konflikty, jeśli uruchomi się dwa razy w ciągu tej samej milisekundy, co jest zdecydowanie możliwe w przypadkach większości ludzi. Lepiej po prostu użyć oficjalnej implementacji tempfile, do takich rzeczy i warunków wyścigu, gdy spróbujesz tego uniknąć. – daboross

4

można przekazać lokalizację pliku w „dir” parametr konstruktora. Działa, jak chcesz.

>>> t = tempfile.NamedTemporaryFile(dir="/Users/rafal") 
>>> t.name 
'/Users/rafal/tmplo45Js' 

Źródło: http://docs.python.org/library/tempfile.html#tempfile.NamedTemporaryFile

+2

info: bez 'delete = False' plik zostanie usunięty, gdy tylko procedura obsługi plików zostanie zamknięta. – gecco

+0

Zakłada to, że wiemy, czym jest reż. – TomOnTime

+0

Znamy to. OP zawiera już pytanie o podział ścieżki na katalog i nazwę pliku, więc nie ma tu miejsca na pisanie o tym tutaj. –

4

aby spełnić wszystkie Państwa kontrolną myślę, że chcesz korzystać z ...

temp = tempfile.NamedTemporaryFile(prefix=data_file_name, dir=path, 
            delete=False) 

Ważne, aby mieć delete=False, bo inaczej:

[...] Jeśli delete jest prawdziwe (domyślne), plik zostanie usunięty, gdy tylko zostanie zamknięty .

+0

Zakłada to, że wiemy, jaka jest ścieżka. – TomOnTime

-1

Używany przez Ciebie moduł tempfile zapewnia bezpieczny sposób zarządzania plikami tymczasowymi. Jeśli naprawdę chcesz korzystać z własnego systemu, powinieneś pamiętać, że może on być podatny na ataki (w szczególności ataki z użyciem dowiązań symbolicznych).

Prosty sposób, aby wygenerować tymczasowej unikalną nazwę pliku (choć dość długą nazwą) jest:

import uuid 
import os 

tempfilename = 'myprefix-%s.dat' % str(uuid.uuid4()) 

with open(tempfilename, 'rw') as tempfile: 
    # do stuff 

os.remove(tempfilename) 

Ale to jest nieco hackish; Naprawdę warto rozważyć użycie modułu tempfile z poprawnymi parametrami prefix i dir przekazanymi do NamedTemporaryFile, jak opisano w innych odpowiedziach.

+0

To jest kuszące, ale widziałem wystarczająco dużo problemów związanych z bezpieczeństwem, spowodowanych przez osoby tnące własnym systemem plików tymczasowych, o których wiem, że używają tego, które zapewnia tempfile. – TomOnTime

+0

Oczywiście użycie czegoś takiego jest złym pomysłem w kodzie produkcji. W środowisku, w którym nie jest to problemem (np. Rejestrowanie danych symulacji), 'uuid' przedstawia sposób generowania unikalnego losowego ciągu znaków. –

Powiązane problemy