Jaki jest najbardziej elegancki sposób sprawdzenia, czy istnieje katalog, w którym ma zostać zapisany plik, a jeśli nie, utwórz katalog za pomocą Pythona? Oto, co próbowałem:
import os
file_path = "/my/directory/filename.txt"
directory = os.path.dirname(file_path)
try:
os.stat(directory)
except:
os.mkdir(directory)
f = file(filename)
Jakoś tęskniłem os.path.exists
(dzięki kanja, Blair i Douglas). Oto co mam teraz:
def ensure_dir(file_path):
directory = os.path.dirname(file_path)
if not os.path.exists(directory):
os.makedirs(directory)
Czy istnieje flaga „otwarta”, która sprawia, że dzieje się to automatycznie?
os.path.mkdir
nie istnieje. Jestos.mkdir
.p
, oto mój fragment kodu:os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True)
Odpowiedzi:
W Pythonie ≥ 3.5 użyj
pathlib.Path.mkdir
:W przypadku starszych wersji Pythona widzę dwie odpowiedzi o dobrych cechach, każda z małą wadą, więc przyjmuję to:
Spróbuj
os.path.exists
i zastanów sięos.makedirs
nad stworzeniem.Jak zauważono w komentarzach i gdzie indziej, istnieje warunek wyścigu - jeśli katalog zostanie utworzony między połączeniami
os.path.exists
i,os.makedirs
połączenieos.makedirs
zakończy się niepowodzeniemOSError
. Niestety łapanieOSError
i kontynuowanie koców nie jest niezawodne, ponieważ zignoruje niepowodzenie tworzenia katalogu z powodu innych czynników, takich jak niewystarczające uprawnienia, pełny dysk itp.Jedną z opcji byłoby przechwycenie
OSError
i sprawdzenie osadzonego kodu błędu (zobacz Czy istnieje wieloplatformowy sposób uzyskiwania informacji z OSError Pythona ):Alternatywnie może istnieć sekunda
os.path.exists
, ale załóżmy, że inny utworzył katalog po pierwszym sprawdzeniu, a następnie usunął go przed drugim - nadal możemy się oszukać.W zależności od aplikacji niebezpieczeństwo równoczesnych operacji może być większe lub mniejsze niż niebezpieczeństwo stwarzane przez inne czynniki, takie jak uprawnienia do plików. Deweloper musiałby dowiedzieć się więcej o konkretnej aplikacji i jej oczekiwanym środowisku przed wybraniem implementacji.
Nowoczesne wersje Pythona znacznie poprawiają ten kod, zarówno poprzez ujawnienie
FileExistsError
(w wersji 3.3 +) ...... i pozwalając argument słowa kluczowego dla
os.makedirs
nazywanyexist_ok
(w 3.2 lub nowszym).źródło
os.path.exists
zwraca równieżTrue
plik. Wysłałem odpowiedź, aby rozwiązać ten problem.exists_ok
parametr,os.makedirs()
którego można użyć, aby opisać, jak obsługiwane jest wcześniejsze istnienie ścieżki, od Python 3.2.os.mkdirs()
może tworzyć niezamierzone foldery, jeśli przypadkowo pominięto separator ścieżki, bieżący folder nie jest zgodny z oczekiwaniami, element ścieżki zawiera separator ścieżki. Jeśli użyjeszos.mkdir()
tych błędów, pojawi się wyjątek, ostrzegający o ich istnieniu.Python 3.5+:
pathlib.Path.mkdir
zgodnie z powyższym rekurencyjnie tworzy katalog i nie zgłasza wyjątku, jeśli katalog już istnieje. Jeśli nie potrzebujesz lub nie chcesz, aby rodzice zostali utworzeni, pomińparents
argument.Python 3.2+:
Używanie
pathlib
:Jeśli możesz, zainstaluj bieżący
pathlib
backport o nazwiepathlib2
. Nie instaluj starszego nieobsługiwanego backportu o nazwiepathlib
. Następnie zapoznaj się z sekcją Python 3.5+ powyżej i użyj jej w ten sam sposób.Jeśli używasz Pythona 3.4, mimo że
pathlib
jest w zestawie, brakuje użytecznejexist_ok
opcji. Backport ma na celu zaoferowanie nowszej i lepszej implementacji,mkdir
która zawiera tę brakującą opcję.Używanie
os
:os.makedirs
zgodnie z powyższym rekurencyjnie tworzy katalog i nie zgłasza wyjątku, jeśli katalog już istnieje. Ma opcjonalnyexist_ok
argument tylko w przypadku używania języka Python 3.2+ z wartością domyślnąFalse
. Ten argument nie istnieje w Pythonie 2.x do wersji 2.7. W związku z tym nie ma potrzeby ręcznego obsługiwania wyjątków, jak w Pythonie 2.7.Python 2.7+:
Używanie
pathlib
:Jeśli możesz, zainstaluj bieżący
pathlib
backport o nazwiepathlib2
. Nie instaluj starszego nieobsługiwanego backportu o nazwiepathlib
. Następnie zapoznaj się z sekcją Python 3.5+ powyżej i użyj jej w ten sam sposób.Używanie
os
:Podczas gdy najpierw można zastosować naiwne rozwiązanie,
os.path.isdir
a następnieos.makedirs
powyższe rozwiązanie odwraca kolejność dwóch operacji. W ten sposób zapobiega powszechnemu wyścigowi związanemu ze zduplikowaną próbą utworzenia katalogu, a także ujednoznacznia pliki z katalogów.Zauważ, że przechwycenie wyjątku i użycie
errno
ma ograniczoną użyteczność, ponieważOSError: [Errno 17] File exists
, tj.errno.EEXIST
Jest podniesiony zarówno dla plików, jak i katalogów. Bardziej niezawodne jest po prostu sprawdzenie, czy katalog istnieje.Alternatywny:
mkpath
tworzy zagnieżdżony katalog i nic nie robi, jeśli katalog już istnieje. Działa to zarówno w Pythonie 2, jak i 3.W przypadku błędu 10948 poważnym ograniczeniem tej alternatywy jest to, że działa ona tylko raz na proces Pythona dla danej ścieżki. Innymi słowy, jeśli użyjesz go do utworzenia katalogu, usuń go z wewnątrz lub z zewnątrz Pythona, a następnie użyj
mkpath
ponownie, aby odtworzyć ten sam katalog,mkpath
po prostu po cichu użyje swoich niepoprawnych informacji buforowanych o wcześniejszym utworzeniu katalogu i nie będzie faktycznie ponownie utwórz katalog. W przeciwieństwie do tego,os.makedirs
nie polega na takiej pamięci podręcznej. To ograniczenie może być odpowiednie w przypadku niektórych aplikacji.Jeśli chodzi o tryb katalogu , zapoznaj się z dokumentacją, jeśli cię to obchodzi.
źródło
os.path.isdir
ktoś inny usuwa folder, podniesiesz niewłaściwy, nieaktualny i mylący błąd, że folder istnieje.Używając try wyjątek i odpowiedni kod błędu z modułu errno pozbywa się warunków wyścigu i działa na różnych platformach:
Innymi słowy, próbujemy utworzyć katalogi, ale jeśli już istnieją, ignorujemy błąd. Z drugiej strony zgłaszany jest każdy inny błąd. Na przykład, jeśli wcześniej utworzysz katalog „a” i usuniesz z niego wszystkie uprawnienia, otrzymasz
OSError
podwyżkę za pomocąerrno.EACCES
(Odmowa dostępu, błąd 13).źródło
exception.errno != errno.EEXIST
, gdy przypadkowo zignoruje przypadek, gdy istnieje ścieżka, ale jest to obiekt niebędący katalogiem, taki jak plik. Najlepiej byłoby, gdyby wyjątek został zgłoszony, jeśli ścieżka nie jest katalogiem.os.makedirs(path,exist_ok=True)
exist_ok
Parametr został wprowadzony w Pythonie 3.2. Nie występuje w Pythonie 2.x. Włączę to do mojej odpowiedzi.Osobiście polecam, abyś użył
os.path.isdir()
do testowania zamiastos.path.exists()
.Jeśli masz:
I głupie dane wejściowe użytkownika:
... Skończysz z katalogiem nazwanym,
filename.etc
gdy przekażesz ten argument,os.makedirs()
jeśli testujeszos.path.exists()
.źródło
Sprawdź
os.makedirs
: (upewnia się, że istnieje pełna ścieżka).Aby obsłużyć fakt, że katalog może istnieć, złap
OSError
. (Jeśliexist_ok
jestFalse
(domyślnie), anOSError
jest podnoszony, jeśli katalog docelowy już istnieje.)źródło
OSError
zostanie podniesiony tutaj, jeśli ścieżka jest istniejącym plikiem lub katalogiem. Wysłałem odpowiedź, aby rozwiązać ten problem.OSError
Przed podjęciem decyzji o zignorowaniu należy sprawdzić warunek błędu podrzędnego . Zobacz stackoverflow.com/a/5032238/763269 .Począwszy od Python 3.5,
pathlib.Path.mkdir
maexist_ok
flagę:To rekurencyjnie tworzy katalog i nie wywołuje wyjątku, jeśli katalog już istnieje.
(tak jak
os.makedirs
dostałexist_ok
flagę zaczynając od python 3.2 np.os.makedirs(path, exist_ok=True)
)źródło
Wgląd w specyfikę tej sytuacji
Dajesz konkretny plik pod określoną ścieżką i wyciągasz katalog ze ścieżki pliku. Następnie po upewnieniu się, że masz katalog, próbujesz otworzyć plik do odczytu. Aby skomentować ten kod:
Chcemy uniknąć nadpisywania funkcji wbudowanego,
dir
. Ponadto,filepath
a możefullfilepath
jest to prawdopodobnie lepsza nazwa semantyczna,filename
dlatego lepiej byłoby napisać:Twoim ostatecznym celem jest otwarcie tego pliku, początkowo twierdzisz, do pisania, ale zasadniczo zbliżasz się do tego celu (na podstawie twojego kodu) w ten sposób, który otwiera plik do odczytu :
Zakładając otwarcie do czytania
Dlaczego miałbyś stworzyć katalog dla pliku, który ma się tam znajdować i być w stanie go odczytać?
Po prostu spróbuj otworzyć plik.
Jeśli katalogu lub pliku nie ma, pojawi
IOError
się powiązany z nim numer błędu:errno.ENOENT
wskaże prawidłowy numer błędu niezależnie od platformy. Możesz go złapać, jeśli chcesz, na przykład:Zakładając, że otwieramy się na pisanie
Jest to prawdopodobnie to, czego chce.
W tym przypadku prawdopodobnie nie mamy żadnych warunków wyścigowych. Więc rób tak, jak byłeś, ale pamiętaj, że aby pisać, musisz otworzyć w
w
trybie (luba
dołączyć). Najlepszą praktyką Pythona jest używanie menedżera kontekstu do otwierania plików.Załóżmy jednak, że mamy kilka procesów w języku Python, które próbują umieścić wszystkie swoje dane w tym samym katalogu. Wtedy możemy mieć spór o utworzenie katalogu. W takim przypadku najlepiej jest zawinąć
makedirs
połączenie w blok try-try.źródło
Wypróbuj
os.path.exists
funkcjęźródło
os.path.mkdir()
metody. Moduł os.path implementuje przydatne funkcje w nazwach ścieżek .Odłożyłem następujące. Nie jest to jednak całkowicie niezawodny.
Teraz, jak mówię, nie jest to tak naprawdę niezawodne, ponieważ istnieje możliwość, że nie uda nam się utworzyć katalogu i innego procesu, który go utworzy w tym okresie.
źródło
os.path.exists
- patrz stackoverflow.com/a/5032238/763269, i (2) powodzenieos.path.exists
nie oznacza, że katalog istnieje, tylko że ścieżka istnieje - może to być plik, dowiązanie symboliczne lub inny obiekt systemu plików.Bezpośrednią odpowiedzią na to jest założenie prostej sytuacji, w której nie spodziewasz się, że inni użytkownicy lub procesy będą bałagać się w twoim katalogu:
lub jeśli utworzenie katalogu podlega warunkom wyścigu (tj. jeśli po sprawdzeniu ścieżki istnieje, coś innego mogło już to zrobić):
Być może jednak jeszcze lepszym rozwiązaniem jest ominięcie problemu rywalizacji o zasoby za pomocą katalogów tymczasowych poprzez
tempfile
:Oto najważniejsze informacje z dokumentu online:
Nowości w Python 3.5:
pathlib.Path
zexist_ok
Jest nowy
Path
obiekt (od wersji 3.4) z wieloma metodami, których chcielibyśmy używać ze ścieżkami - jedną z nich jestmkdir
.(Dla kontekstu śledzę mojego cotygodniowego przedstawiciela za pomocą skryptu. Oto odpowiednie części kodu ze skryptu, które pozwalają mi uniknąć uderzenia przepełnienia stosu więcej niż raz dziennie dla tych samych danych.)
Najpierw odpowiedni przywóz:
Nie musimy się
os.path.join
teraz zajmować - po prostu połącz części ścieżki za pomocą/
:Następnie idempotentnie upewniam się, że katalog istnieje -
exist_ok
argument pojawia się w Pythonie 3.5:Oto odpowiednia część dokumentacji :
Oto trochę więcej skryptu - w moim przypadku nie podlegam warunkom wyścigowym, mam tylko jeden proces, który oczekuje, że katalog (lub zawarte pliki) tam będzie, i nie mam nic, co próbuje usunąć katalog.
Path
obiekty muszą zostać wymuszone,str
zanim inne interfejsy API oczekującestr
ścieżek będą mogły ich używać.Może Pandy powinny być aktualizowane, aby zaakceptować wystąpień abstrakcyjnej klasy bazowej
os.PathLike
.źródło
W Pythonie 3.4 możesz także użyć zupełnie nowego
pathlib
modułu :źródło
pathlib
i gdziepathlib2
dla nowych użytkowników, i myślę, że profesjonaliści tutaj dowiedzą się o wycofaniu;)Odpowiedniej dokumentacji Python sugeruje zastosowanie EAFP styl kodowania (łatwiej jest prosić o przebaczenie niż uprawnienia) . Oznacza to, że kod
jest lepszy niż alternatywa
Dokumentacja sugeruje to właśnie ze względu na warunki wyścigu omówione w tym pytaniu. Ponadto, jak wspominają inni, przewaga kwerendy w stosunku do jednego systemu operacyjnego jest większa. Wreszcie argument wysunięty potencjalnie na korzyść drugiego kodu w niektórych przypadkach - gdy programista zna środowisko, w którym działa aplikacja - może być popierany tylko w szczególnym przypadku, w którym program skonfigurował środowisko prywatne dla sam (i inne wystąpienia tego samego programu).
Nawet w takim przypadku jest to zła praktyka i może prowadzić do długiego bezużytecznego debugowania. Na przykład fakt, że ustawiamy uprawnienia do katalogu, nie powinien pozostawiać nas z uprawnieniami do wyświetlania są odpowiednio ustawione dla naszych celów. Katalog nadrzędny można podłączyć z innymi uprawnieniami. Zasadniczo program powinien zawsze działać poprawnie, a programista nie powinien oczekiwać jednego określonego środowiska.
źródło
W Python3 ,
os.makedirs
ustawienie podporyexist_ok
. Ustawieniem domyślnym jestFalse
, co oznacza, żeOSError
zostanie podniesiony, jeśli katalog docelowy już istnieje. Ustawiającexist_ok
sięTrue
,OSError
(istnieje katalog) będą ignorowane i katalog nie zostanie utworzony.W python2 ,
os.makedirs
nie obsługuje ustawieniaexist_ok
. Możesz użyć tego podejścia w odpowiedzi heikki-toivonen :źródło
W przypadku rozwiązania jednowarstwowego możesz użyć
IPython.utils.path.ensure_dir_exists()
:Z dokumentacji : Upewnij się, że istnieje katalog. Jeśli nie istnieje, spróbuj go utworzyć i zabezpieczyć przed warunkami wyścigu, jeśli robi to inny proces.
źródło
IPython
ma gwarancji, że moduł będzie obecny. Jest natywnie obecny na moim Macu, ale nie na żadnej z moich instalacji Linuksa w Pythonie. Zasadniczo nie jest to jeden z modułów wymienionych w indeksie modułów Pythona .pip install ipython
lub zawierać zależność w swoim requirements.txt lub pom.xml . Dokumentacja: ipython.org/install.htmlMożesz użyć
mkpath
Pamiętaj, że utworzy także katalogi przodków.
Działa dla Python 2 i 3.
źródło
distutils.dir_util
nie jest częścią publicznego interfejsu API distutil i ma problemy w środowiskach wielowątkowych: bugs.python.org/issue10948distutils.dir_util.mkpath
polega na tym, że jeśli utworzysz katalog, a następnie usuniesz go z wnętrza lub z zewnątrz Pythona, a następnie użyjeszmkpath
ponownie,mkpath
po prostu użyje swoich niepoprawnych informacji z pamięci podręcznej o wcześniejszym utworzeniu katalogu i będzie nie tworzy ponownie katalogu. W przeciwieństwie do tego,os.makedirs
nie polega na takiej pamięci podręcznej.Używam
os.path.exists()
, oto skrypt w języku Python 3, którego można użyć do sprawdzenia, czy katalog istnieje, utwórz go, jeśli nie istnieje, i usuń, jeśli istnieje (w razie potrzeby).Monituje użytkowników o wprowadzenie katalogu i może być łatwo modyfikowany.
źródło
Możesz użyć
os.listdir
do tego:źródło
Znalazłem to pytanie i początkowo byłem zaskoczony niektórymi błędami i błędami, które otrzymywałem. Pracuję w Pythonie 3 (v.3.5 w środowisku wirtualnym Anaconda w systemie Arch Linux x86_64).
Rozważ tę strukturę katalogów:
Oto moje eksperymenty / notatki, które wyjaśniają rzeczy:
Wniosek: moim zdaniem „metoda 2” jest bardziej niezawodna.
[1] Jak mogę utworzyć katalog, jeśli nie istnieje?
[2] https://docs.python.org/3/library/os.html#os.makedirs
źródło
Zobaczyłem odpowiedzi Heikki Toivonen i ABB i pomyślałem o tej odmianie.
źródło
Użyj tego polecenia sprawdź i utwórz katalog
źródło
Dlaczego nie użyć modułu podprocesu, jeśli działa na komputerze obsługującym polecenie
mkdir
z-p
opcją? Działa na Python 2.7 i Python 3.6Powinien załatwić sprawę w większości systemów.
W sytuacjach, w których przenośność nie ma znaczenia (np. Przy użyciu dokera) rozwiązaniem są czyste 2 linie. Nie musisz także dodawać logiki, aby sprawdzić, czy katalogi istnieją, czy nie. Wreszcie, można bezpiecznie uruchomić ponownie bez żadnych skutków ubocznych
Jeśli potrzebujesz obsługi błędów:
źródło
Jeśli weźmiesz pod uwagę następujące kwestie:
oznacza, że istnieje katalog (ścieżka) AND to katalog. Więc dla mnie w ten sposób robi to, czego potrzebuję. Mogę więc upewnić się, że jest to folder (a nie plik) i że istnieje.
źródło
Wywołaj funkcję
create_dir()
w punkcie wejścia programu / projektu.źródło
Musisz ustawić pełną ścieżkę przed utworzeniem katalogu:
To działa dla mnie i mam nadzieję, że zadziała również dla ciebie
źródło
Spowoduje to sprawdzenie, czy plik istnieje, jeśli go nie ma, to go utworzy.
źródło