Jak sprawdzić, czy plik istnieje, czy nie, bez użycia tryinstrukcji?
Jak sprawdzić, czy plik istnieje, czy nie, bez użycia tryinstrukcji?
Odpowiedzi:
Jeśli sprawdzasz, że możesz zrobić coś takiego if file_exists: open_it(), bezpieczniej jest skorzystać tryz próby otwarcia. Sprawdzanie, a następnie otwieranie grozi usunięciem lub przeniesieniem pliku lub czymś innym między sprawdzaniem a próbą otwarcia.
Jeśli nie planujesz natychmiast otworzyć pliku, możesz użyć os.path.isfile
Zwróć,
Truejeśli ścieżka jest istniejącym zwykłym plikiem. Podąża za dowiązaniami symbolicznymi, więc zarówno islink (), jak i isfile () mogą być prawdziwe dla tej samej ścieżki.
import os.path
os.path.isfile(fname)
jeśli musisz się upewnić, że jest to plik.
Począwszy od Python 3.4, pathlibmoduł oferuje podejście obiektowe (przeniesione do pathlib2Pythona 2.7):
from pathlib import Path
my_file = Path("/path/to/file")
if my_file.is_file():
# file exists
Aby sprawdzić katalog, wykonaj:
if my_file.is_dir():
# directory exists
Aby sprawdzić, czy Pathobiekt istnieje niezależnie od tego, czy jest to plik czy katalog, użyj exists():
if my_file.exists():
# path exists
Możesz także użyć resolve(strict=True)w trybloku:
try:
my_abs_path = my_file.resolve(strict=True)
except FileNotFoundError:
# doesn't exist
else:
# exists
FileNotFoundErrorzostał wprowadzony w Pythonie 3. Jeśli potrzebujesz także obsługiwać Python 2.7 oraz Python 3, możesz IOErrorzamiast tego użyć (które FileNotFoundErrorpodklasy) stackoverflow.com/a/21368457/1960959
open('file', 'r+')), a następnie przejść do końca.
Masz os.path.existsfunkcję:
import os.path
os.path.exists(file_path)
Zwraca Truezarówno pliki, jak i katalogi, ale możesz zamiast tego użyć
os.path.isfile(file_path)
aby sprawdzić, czy jest to konkretnie plik. Podąża za dowiązaniami symbolicznymi.
W przeciwieństwie do isfile(), exists()wróci Truepo katalogi. W zależności od tego, czy chcesz tylko zwykłe pliki, czy też katalogi, użyjesz isfile()lub exists(). Oto kilka prostych wyników REPL:
>>> os.path.isfile("/etc/password.txt")
True
>>> os.path.isfile("/etc")
False
>>> os.path.isfile("/does/not/exist")
False
>>> os.path.exists("/etc/password.txt")
True
>>> os.path.exists("/etc")
True
>>> os.path.exists("/does/not/exist")
False
Użyj os.path.isfile()z os.access():
import os
PATH = './file.txt'
if os.path.isfile(PATH) and os.access(PATH, os.R_OK):
print("File exists and is readable")
else:
print("Either the file is missing or not readable")
os.access()zwróci false.
import osmusisz tego robić, import os.pathponieważ jest to już część os. Musisz tylko zaimportować, os.pathjeśli zamierzasz używać funkcji z siebie, os.patha nie od ossiebie, aby zaimportować mniejszą rzecz, ale podczas używania os.accessi os.R_OKdrugi import nie jest potrzebny.
import os
os.path.exists(path) # Returns whether the path (directory or file) exists or not
os.path.isfile(path) # Returns whether the file exists or not
Chociaż prawie każdy możliwy sposób został wymieniony w (przynajmniej jednej) istniejących odpowiedziach (np. Dodano specyficzne rzeczy w Pythonie 3.4 ), spróbuję pogrupować wszystko razem.
Uwaga : każdy fragment standardowego kodu biblioteki Python, który zamierzam opublikować, należy do wersji 3.5.3 .
Opis problemu :
Możliwe rozwiązania :
[Python 3]: os.path. istnieje ( ścieżka ) (też sprawdzić innych członków rodziny, takich jak funkcja os.path.isfile, os.path.isdir, os.path.lexistsdla nieco odmiennych zachowań)
os.path.exists(path)
Zwraca,
Truejeśli ścieżka odnosi się do istniejącej ścieżki lub otwartego deskryptora pliku. ZwracaFalseza zepsute dowiązania symboliczne. Na niektórych platformach funkcja ta może zwrócić,Falsejeśli nie zostanie udzielone uprawnienie do wykonania os.stat () na żądanym pliku, nawet jeśli ścieżka istnieje fizycznie.
Wszystko dobrze, ale jeśli śledzisz drzewo importu:
os.path- posixpath.py ( ntpath.py )
genericpath.py , linia ~ # 20 +
def exists(path):
"""Test whether a path exists. Returns False for broken symbolic links"""
try:
st = os.stat(path)
except os.error:
return False
return Trueto tylko próba / z wyjątkiem bloku wokół [Python 3]: os. stat ( ścieżka, *, dir_fd = Brak, follow_symlinks = True ) . Więc twój kod jest wypróbowany / z wyjątkiem darmowego, ale na dole framestacka jest (przynajmniej) jeden taki blok. Dotyczy to również innych funkcji (w tym os.path.isfile ).
1.1 [Python 3]: Ścieżka. is_file ()
Pod maską robi dokładnie to samo ( pathlib.py , linia ~ # 1330 ):
def is_file(self):
"""
Whether this path is a regular file (also True for symlinks pointing
to regular files).
"""
try:
return S_ISREG(self.stat().st_mode)
except OSError as e:
if e.errno not in (ENOENT, ENOTDIR):
raise
# Path doesn't exist or is a broken symlink
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
return False[Python 3]: Z menedżerami kontekstu instrukcji . Zarówno:
Stworzyć jeden:
class Swallow: # Dummy example
swallowed_exceptions = (FileNotFoundError,)
def __enter__(self):
print("Entering...")
def __exit__(self, exc_type, exc_value, exc_traceback):
print("Exiting:", exc_type, exc_value, exc_traceback)
return exc_type in Swallow.swallowed_exceptions # only swallow FileNotFoundError (not e.g. TypeError - if the user passes a wrong argument like None or float or ...)
I jego użycie - powtórzę to os.path.isfilezachowanie (pamiętaj, że jest to tylko w celach demonstracyjnych, nie próbuj pisać takiego kodu do produkcji ):
import os
import stat
def isfile_seaman(path): # Dummy func
result = False
with Swallow():
result = stat.S_ISREG(os.stat(path).st_mode)
return resultUżyj [Python 3]: contextlib. suppress ( * wyjątki ) - który został specjalnie zaprojektowany do selektywnego tłumienia wyjątków
Ale wydają się być owijarki ponad próbie / z wyjątkiem / else / wreszcie bloki, jak [Python 3]: z rachunku stanów:
Pozwala to na powszechną próbę ... z wyjątkiem ... wreszcie , aby wzorce użycia zostały zamknięte w celu wygodnego ponownego użycia.
Funkcje przechodzenia przez system plików (i wyszukaj wyniki dla pasujących elementów)
[Python 3]: os. listdir ( ścieżka = '.' ) (lub [Python 3]: os. scandir ( ścieżka = '.' ) w Pythonie w wersji 3.5 +, backport: [PyPI]: scandir )
Obaj używają pod maską:
przez [GitHub]: python / cpython - (master) cpython / Modules / posixmodule.c
Użycie scandir () zamiast listdir () może znacznie zwiększyć wydajność kodu, który również potrzebuje informacji o typie pliku lub atrybucie pliku, ponieważ obiekty os.DirEntry ujawniają te informacje, jeśli system operacyjny udostępnia je podczas skanowania katalogu. Wszystkie metody os.DirEntry mogą wykonywać wywołanie systemowe, ale is_dir () i is_file () zwykle wymagają tylko wywołania systemowego dla dowiązań symbolicznych; os.DirEntry.stat () zawsze wymaga wywołania systemowego w systemie Unix, ale wymaga tylko jednego dla dowiązań symbolicznych w systemie Windows.
os.listdir( os.scandirgdy dostępne)glob.glob)
os.listdir
Ponieważ powtarzają się one po folderach (w większości przypadków) są nieefektywne w przypadku naszego problemu (są wyjątki, takie jak glob bing bez symboli wieloznacznych - jak wskazał @ShadowRanger), więc nie będę nalegał na nie. Nie wspominając o tym, że w niektórych przypadkach przetwarzanie plików może być wymagane.
[Python 3]: os. access ( ścieżka, tryb, *, dir_fd = Brak, efektywne_ids = Fałsz, follow_symlinks = True ), którego zachowanie jest bliskie os.path.exists(w rzeczywistości jest szersze, głównie z powodu drugiego argumentu)
... sprawdź, czy wywołujący użytkownik ma określony dostęp do ścieżki . tryb powinien być F_OK, aby sprawdzić istnienie ścieżki ...
os.access("/tmp", os.F_OK)
Ponieważ pracuję także w C , używam tej metody, jak również dlatego, że pod maską, wywołuje natywne API s (znów przez „$ {PYTHON_SRC_DIR} /Modules/posixmodule.c” ), ale także otwiera furtkę dla ewentualnego użytkownika błędy i nie jest tak Python ic jak inne warianty. Tak jak słusznie zauważył @AaronHall, nie używaj go, chyba że wiesz, co robisz:
Uwaga : wywoływanie natywnego API jest również możliwe przez [Python 3]: ctypes - Biblioteka funkcji obcych dla Pythona , ale w większości przypadków jest bardziej skomplikowana.
(W szczególności dla Win ): Ponieważ vcruntime * ( msvcr * ) .dll eksportuje [MS.Docs]: _access, a także rodzinę funkcji _waccess , oto przykład:
Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import os, ctypes >>> ctypes.CDLL("msvcrt")._waccess(u"C:\\Windows\\System32\\cmd.exe", os.F_OK) 0 >>> ctypes.CDLL("msvcrt")._waccess(u"C:\\Windows\\System32\\cmd.exe.notexist", os.F_OK) -1
Uwagi :
os.F_OKtego połączenia, ale to tylko dla jasności (jego wartość wynosi 0 )
Odpowiednik Lnx ( Ubtu (16 x64) ):
Python 3.5.2 (default, Nov 17 2016, 17:05:23) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import os, ctypes >>> ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6").access(b"/tmp", os.F_OK) 0 >>> ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6").access(b"/tmp.notexist", os.F_OK) -1
Uwagi :
Zamiast tego na stałe ścieżka libc ( „/lib/x86_64-linux-gnu/libc.so.6” ), która może (i najprawdopodobniej będzie się różnić) w różnych systemach, Brak (lub pusty ciąg) może zostać przekazany do konstruktora CDLL ( ctypes.CDLL(None).access(b"/tmp", os.F_OK)). Według [man7]: DLOPEN (3) :
Jeśli nazwa pliku ma wartość NULL, wówczas zwrócony uchwyt dotyczy programu głównego. Po przekazaniu do dlsym () uchwyt ten powoduje wyszukiwanie symbolu w programie głównym, a następnie wszystkie obiekty współdzielone ładowane podczas uruchamiania programu, a następnie wszystkie obiekty współdzielone ładowane przez dlopen () z flagą RTLD_GLOBAL .
__declspec(dllexport)(dlaczego na Ziemi zwykła osoba miałaby to robić?), główny program jest wczytywalny, ale praktycznie bezużytecznyZainstaluj moduł innej firmy z funkcjami systemu plików
Najprawdopodobniej będzie polegać na jednym z powyższych sposobów (może z niewielkimi dostosowaniami).
Jednym z przykładów byłoby (ponownie, specyficzne dla Win ) [GitHub]: mhammond / pywin32 - Rozszerzenia Python dla Windows (pywin32) , które są opakowaniem Pythona w WINAPI .
Ale ponieważ jest to raczej obejście, zatrzymuję się tutaj.
Innym (kiepskim) obejściem ( gainarie ) jest (jak to nazywam) podejście sysadmin : użyj Pythona jako opakowania do wykonywania poleceń powłoki
Wygraj :
(py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe\" > nul 2>&1'))" 0 (py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe.notexist\" > nul 2>&1'))" 1
Nix ( Lnx ( Ubtu )):
[cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp\" > /dev/null 2>&1'))" 0 [cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp.notexist\" > /dev/null 2>&1'))" 512
Dolna linia :
Uwagi końcowe :
glob.iglob(i glob.globrównież) są oparteos.scandir , więc teraz jest leniwy; aby uzyskać pierwsze trafienie w katalogu 10 mln plików, skanujesz tylko do momentu osiągnięcia pierwszego trafienia. A nawet w wersji wcześniejszej niż 3.6, jeśli używasz globmetod bez symboli wieloznacznych, funkcja jest inteligentna: wie, że możesz mieć tylko jedno trafienie, więc upraszcza globowanie tylko doos.path.isdiros.path.lexists ( lub w zależności od tego, czy ścieżka się kończy /).
os.path.isdirlub os.path.lexistponieważ jest to zbiór wywołań i ciągów funkcji poziomu Pythona operacje, zanim zdecyduje, że efektywna ścieżka jest opłacalna, ale nie wymaga dodatkowego wywołania systemowego ani pracy we / wy, która jest o rząd wielkości wolniejsza).
Jest to najprostszy sposób sprawdzenia, czy plik istnieje. Tylko dlatego, że plik istniał po sprawdzeniu, nie gwarantuje , że będzie tam, kiedy trzeba go otworzyć.
import os
fname = "foo.txt"
if os.path.isfile(fname):
print("file does exist at this time")
else:
print("no such file exists at this time")
Python 3.4+ ma obiektowy moduł ścieżki: pathlib . Za pomocą tego nowego modułu możesz sprawdzić, czy plik istnieje w następujący sposób:
import pathlib
p = pathlib.Path('path/to/file')
if p.is_file(): # or p.is_dir() to see if it is a directory
# do stuff
Możesz (i zwykle powinieneś) nadal używać try/exceptbloku podczas otwierania plików:
try:
with p.open() as f:
# do awesome stuff
except OSError:
print('Well darn.')
Moduł pathlib zawiera wiele fajnych rzeczy: wygodne globowanie, sprawdzanie właściciela pliku, łatwiejsze dołączanie ścieżki itp. Warto to sprawdzić. Jeśli korzystasz ze starszego Pythona (wersja 2.6 lub nowsza), nadal możesz zainstalować pathlib za pomocą pip:
# installs pathlib2 on older Python versions
# the original third-party module, pathlib, is no longer maintained.
pip install pathlib2
Następnie zaimportuj go w następujący sposób:
# Older Python versions
import pathlib2 as pathlib
Wolę instrukcję try. Jest uważany za lepszy styl i pozwala uniknąć warunków wyścigowych.
Nie wierz mi na słowo. Istnieje mnóstwo poparcia dla tej teorii. Oto kilka:
try...excepttak nie pomaga rozwiązać tego problemu.
except:klauzuli sprawi, że wyjątek powstający w tej części kodu wywoła mylący komunikat (drugi błąd zgłoszony podczas przetwarzanie pierwszego.)
Jak sprawdzić, czy plik istnieje, używając Pythona, bez użycia instrukcji try?
Teraz dostępny od Pythona 3.4, importuj i tworzymy instancję Pathobiektu o nazwie pliku, i sprawdź is_filemetodę (zauważ, że to zwraca True dla dowiązań symbolicznych wskazujących również na zwykłe pliki):
>>> from pathlib import Path
>>> Path('/').is_file()
False
>>> Path('/initrd.img').is_file()
True
>>> Path('/doesnotexist').is_file()
False
Jeśli korzystasz z Python 2, możesz backportować moduł pathlib z pypi pathlib2lub w inny sposób sprawdzić isfilez os.pathmodułu:
>>> import os
>>> os.path.isfile('/')
False
>>> os.path.isfile('/initrd.img')
True
>>> os.path.isfile('/doesnotexist')
False
Teraz powyższe jest prawdopodobnie najlepszą pragmatyczną bezpośrednią odpowiedzią tutaj, ale istnieje możliwość wyścigu (w zależności od tego, co próbujesz osiągnąć) oraz fakt, że podstawowa implementacja używa try, ale Python używa trywszędzie w swojej implementacji.
Ponieważ Python używa trywszędzie, naprawdę nie ma powodu, aby unikać implementacji, która go używa.
Ale reszta tej odpowiedzi próbuje rozważyć te zastrzeżenia.
Dostępne od wersji Python 3.4, użyj nowego Pathobiektu w pathlib. Zauważ, że .existsto nie do końca prawda, ponieważ katalogi nie są plikami (z wyjątkiem tego, że w Uniksie wszystko jest plikiem).
>>> from pathlib import Path
>>> root = Path('/')
>>> root.exists()
True
Musimy więc użyć is_file:
>>> root.is_file()
False
Oto pomoc dotycząca is_file:
is_file(self)
Whether this path is a regular file (also True for symlinks pointing
to regular files).
Pobierzmy więc plik, o którym wiemy, że to plik:
>>> import tempfile
>>> file = tempfile.NamedTemporaryFile()
>>> filepathobj = Path(file.name)
>>> filepathobj.is_file()
True
>>> filepathobj.exists()
True
Domyślnie NamedTemporaryFileusuwa plik po zamknięciu (i zostanie automatycznie zamknięty, gdy nie będzie już więcej odwołań do niego).
>>> del file
>>> filepathobj.exists()
False
>>> filepathobj.is_file()
False
Jeśli jednak zagłębisz się w implementację , zobaczysz, że is_fileużywa try:
def is_file(self):
"""
Whether this path is a regular file (also True for symlinks pointing
to regular files).
"""
try:
return S_ISREG(self.stat().st_mode)
except OSError as e:
if e.errno not in (ENOENT, ENOTDIR):
raise
# Path doesn't exist or is a broken symlink
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
return False
Lubimy to, tryponieważ pozwala uniknąć warunków wyścigowych. Dzięki trypo prostu próbujesz odczytać plik, oczekując, że on tam będzie, a jeśli nie, wychwytujesz wyjątek i wykonujesz dowolne zachowanie rezerwowe, które ma sens.
Jeśli chcesz sprawdzić, czy plik istnieje, zanim spróbujesz go odczytać, być może usuwasz go, a następnie korzystasz z wielu wątków lub procesów lub inny program wie o tym pliku i może go usunąć - ryzykujesz wyścigu sprawdzając istnieje, bo są wtedy wyścigi , aby otworzyć go przed jego stanu (jego istnienie) zmienia.
Warunki wyścigu są bardzo trudne do debugowania, ponieważ istnieje bardzo małe okno, w którym mogą spowodować awarię programu.
Ale jeśli to jest twoja motywacja, to można uzyskać wartość tryrachunku za pomocą suppressmenedżera kontekstowe.
suppressPython 3.4 udostępnia nam suppressmenedżera kontekstu (wcześniej ignoremenedżera kontekstu), który robi semantycznie dokładnie to samo w mniejszej liczbie wierszy, a jednocześnie (przynajmniej powierzchownie) spełnia oryginalne zapytanie o uniknięcie tryinstrukcji:
from contextlib import suppress
from pathlib import Path
Stosowanie:
>>> with suppress(OSError), Path('doesnotexist').open() as f:
... for line in f:
... print(line)
...
>>>
>>> with suppress(OSError):
... Path('doesnotexist').unlink()
...
>>>
W przypadku wcześniejszych Pytonów możesz rzucić własne suppress, ale bez nich trybędzie bardziej gadatliwy niż z. Wierzę, że tak naprawdę jest to jedyna odpowiedź, która nie jest używana tryna żadnym poziomie w Pythonie, którą można zastosować przed Pythonem 3.4, ponieważ zamiast tego używa menedżera kontekstu:
class suppress(object):
def __init__(self, *exceptions):
self.exceptions = exceptions
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None:
return issubclass(exc_type, self.exceptions)
Być może łatwiejsze z próbą:
from contextlib import contextmanager
@contextmanager
def suppress(*exceptions):
try:
yield
except exceptions:
pass
plik is
import os
os.path.isfile(path)
z dokumentów :
os.path.isfile(path)Zwraca wartość True, jeśli ścieżka jest istniejącym zwykłym plikiem. Wynika to dowiązania symboliczne, tak jak
islink()iisfile()może być prawdziwe w odniesieniu do tej samej ścieżce.
Ale jeśli zbadasz źródło tej funkcji, zobaczysz, że faktycznie używa instrukcji try:
# This follows symbolic links, so both islink() and isdir() can be true # for the same path on systems that support symlinks def isfile(path): """Test whether a path is a regular file""" try: st = os.stat(path) except os.error: return False return stat.S_ISREG(st.st_mode)
>>> OSError is os.error
True
Wystarczy, że użyje podanej ścieżki, aby sprawdzić, czy może uzyskać statystyki, przechwytuje, OSErrora następnie sprawdza, czy jest to plik, jeśli nie zgłosił wyjątku.
Jeśli zamierzasz coś zrobić z plikiem, sugerowałbym bezpośrednią próbę spróbowania, z wyjątkiem uniknięcia wyścigu:
try:
with open(path) as f:
f.read()
except OSError:
pass
os.access
Dostępny jest dla systemów Unix i Windows os.access, ale aby go użyć, musisz przekazać flagi i nie rozróżnia on plików i katalogów. Jest to bardziej wykorzystywane do testowania, czy rzeczywisty wywołujący użytkownik ma dostęp w środowisku o podwyższonych uprawnieniach:
import os
os.access(path, os.F_OK)
Ma także takie same problemy z wyścigiem jak isfile. Z dokumentów :
Uwaga: Użycie access () do sprawdzenia, czy użytkownik jest upoważniony np. Do otwarcia pliku, zanim faktycznie to zrobi, użycie open () tworzy lukę w zabezpieczeniach, ponieważ użytkownik może wykorzystać krótki odstęp czasu między sprawdzeniem a otwarciem pliku, aby nim manipulować. Lepiej jest stosować techniki EAFP. Na przykład:
if os.access("myfile", os.R_OK): with open("myfile") as fp: return fp.read() return "some default data"lepiej napisać jako:
try: fp = open("myfile") except IOError as e: if e.errno == errno.EACCES: return "some default data" # Not a permission error. raise else: with fp: return fp.read()
Unikaj używania os.access. Jest to funkcja niskiego poziomu, która ma więcej możliwości wystąpienia błędu użytkownika niż obiekty i funkcje wyższego poziomu omówione powyżej.
Inna odpowiedź mówi o tym os.access:
Osobiście wolę ten, ponieważ pod maską wywołuje natywne interfejsy API (przez „$ {PYTHON_SRC_DIR} /Modules/posixmodule.c”), ale otwiera także bramę dla możliwych błędów użytkownika i nie jest tak Pythonic jak inne warianty :
Ta odpowiedź mówi, że woli bez skłonności do Pythona, podatna na błędy, bez uzasadnienia. Wygląda na to, że zachęca użytkowników do korzystania z niskopoziomowych interfejsów API bez ich zrozumienia.
Tworzy również menedżera kontekstu, który poprzez bezwarunkowe zwracanie Truepozwala wszystkim wyjątkom (w tym KeyboardInterrupti SystemExit!) Przejść cicho, co jest dobrym sposobem na ukrycie błędów.
Wydaje się, że zachęca to użytkowników do stosowania złych praktyk.
import os
#Your path here e.g. "C:\Program Files\text.txt"
#For access purposes: "C:\\Program Files\\text.txt"
if os.path.exists("C:\..."):
print "File found!"
else:
print "File not found!"
Importowanie osułatwia nawigację i wykonywanie standardowych działań w systemie operacyjnym.
W celach informacyjnych zobacz także Jak sprawdzić, czy plik istnieje za pomocą Pythona?
Jeśli potrzebujesz operacji na wysokim poziomie, użyj shutil.
os.path.existszwraca true dla rzeczy, które nie są plikami, takich jak katalogi. To daje wyniki fałszywie pozytywne. Zobacz inne odpowiedzi, które zalecają os.path.isfile.
Testowanie plików i folderów z os.path.isfile(), os.path.isdir()ios.path.exists()
Zakładając, że „ścieżka” jest prawidłową ścieżką, ta tabela pokazuje, co każda funkcja zwraca do plików i folderów:
Możesz również przetestować, czy plik jest określonego typu, używając go os.path.splitext()do uzyskania rozszerzenia (jeśli jeszcze go nie znasz)
>>> import os
>>> path = "path to a word document"
>>> os.path.isfile(path)
True
>>> os.path.splitext(path)[1] == ".docx" # test if the extension is .docx
True
W 2016 roku najlepszym sposobem jest nadal os.path.isfile:
>>> os.path.isfile('/path/to/some/file.txt')
Lub w Python 3 możesz użyć pathlib:
import pathlib
path = pathlib.Path('/path/to/some/file.txt')
if path.is_file():
...
pathlibjest rozwiązaniem OOP dla ścieżek w Pythonie. Dzięki temu możesz zrobić znacznie więcej. Jeśli potrzebujesz tylko sprawdzić istnienie, przewaga nie jest tak duża.
Nie wydaje się, aby istniała znacząca funkcjonalna różnica między try / wyjątkiem a isfile(), więc powinieneś użyć tego, który ma sens.
Jeśli chcesz odczytać plik, jeśli istnieje, zrób to
try:
f = open(filepath)
except IOError:
print 'Oh dear.'
Ale jeśli chcesz tylko zmienić nazwę pliku, jeśli istnieje, i dlatego nie musisz go otwierać, zrób to
if os.path.isfile(filepath):
os.rename(filepath, filepath + '.old')
Jeśli chcesz zapisać do pliku, jeśli nie istnieje, zrób to
# python 2
if not os.path.isfile(filepath):
f = open(filepath, 'w')
# python 3, x opens for exclusive creation, failing if the file already exists
try:
f = open(filepath, 'wx')
except IOError:
print 'file already exists'
Jeśli potrzebujesz blokowania plików, to inna sprawa.
os.path.existszwraca true dla rzeczy, które nie są plikami, takich jak katalogi. To daje wyniki fałszywie pozytywne. Zobacz inne odpowiedzi, które zalecają os.path.isfile.
filepathodpowiednim czasie, a BAM zastępujesz plik docelowy. Powinieneś zrobić open(filepath, 'wx')w try...exceptbloku, aby uniknąć problemu.
OSErrorjeśli filepath + '.old'już istnieje”: „W systemie Windows, jeśli dst już istnieje, OSError zostanie podniesiony, nawet jeśli jest to plik; może nie być możliwości zaimplementowania atomowej zmiany nazwy, gdy dst nazywa istniejący plik. ”
os.replace przenośnie wykonuje cichą zamianę pliku docelowego (jest identyczny z os.renamezachowaniem Linuxa) (błąd tylko wtedy, gdy istnieje nazwa docelowa i jest katalogiem). Więc utknąłeś na wersji 2.x, ale użytkownicy Py3 mają dobrą opcję od kilku lat.
renameprzykładzie: należy to zrobić za pomocą try/ except. os.rename(lub os.replacena współczesnym Pythonie) jest atomowy; sprawdzanie, a następnie zmiana nazwy wprowadza niepotrzebny wyścig i dodatkowe wywołania systemowe. Po prostu zróbtry: os.replace(filepath, filepath + '.old') except OSError: pass
Możesz spróbować (bezpieczniej):
try:
# http://effbot.org/zone/python-with-statement.htm
# 'with' is safer to open a file
with open('whatever.txt') as fh:
# Do something with 'fh'
except IOError as e:
print("({})".format(e))
Wyjście byłoby:
([Errno 2] Brak takiego pliku lub katalogu: „okolwiek.txt ”)
Następnie, w zależności od wyniku, twój program może po prostu dalej działać od tego miejsca lub możesz napisać kod, aby go zatrzymać, jeśli chcesz.
try
Chociaż zawsze polecam używanie tryi exceptoświadczenia, oto kilka możliwości dla ciebie (mój osobisty faworyt używa os.access):
Spróbuj otworzyć plik:
Otwarcie pliku zawsze weryfikuje jego istnienie. Możesz zrobić taką funkcję:
def File_Existence(filepath):
f = open(filepath)
return True
Jeśli ma wartość False, przestanie działać z nieobsługiwanym IOError lub OSError w późniejszych wersjach Pythona. Aby złapać wyjątek, musisz użyć klauzuli try oprócz. Oczywiście zawsze możesz użyć tryinstrukcji wyjątku w ten sposób (dzięki hsandt
za zmuszenie mnie do myślenia):
def File_Existence(filepath):
try:
f = open(filepath)
except IOError, OSError: # Note OSError is for later versions of Python
return False
return TrueUżyj os.path.exists(path):
Spowoduje to sprawdzenie istnienia tego, co określisz. Sprawdza jednak pliki i katalogi, więc uważaj na to, jak z nich korzystasz.
import os.path
>>> os.path.exists("this/is/a/directory")
True
>>> os.path.exists("this/is/a/file.txt")
True
>>> os.path.exists("not/a/directory")
FalseUżyj os.access(path, mode):
Spowoduje to sprawdzenie, czy masz dostęp do pliku. Sprawdzi uprawnienia. W oparciu o dokumentację os.py, wpisując os.F_OK, sprawdzi istnienie ścieżki. Jednak użycie tego spowoduje powstanie luki w zabezpieczeniach, ponieważ ktoś może zaatakować twój plik, wykorzystując czas między sprawdzeniem uprawnień a otwarciem pliku. Zamiast tego powinieneś przejść bezpośrednio do otwierania pliku zamiast sprawdzania jego uprawnień. ( EAFP vs LBYP ). Jeśli nie zamierzasz później otwierać pliku i sprawdzasz tylko jego istnienie, możesz tego użyć.
W każdym razie tutaj:
>>> import os
>>> os.access("/is/a/file.txt", os.F_OK)
TruePowinienem także wspomnieć, że istnieją dwa sposoby, aby nie można było zweryfikować istnienia pliku. Albo będzie to problem, permission deniedalbo no such file or directory. Jeśli złapiesz IOError, ustaw IOError as e(jak moja pierwsza opcja), a następnie wpisz, print(e.args)aby, miejmy nadzieję, ustalić problem. Mam nadzieję, że to pomoże! :)
Data: 04.12.2017
Każde możliwe rozwiązanie zostało wymienione w innych odpowiedziach.
Intuicyjny i dyskusyjny sposób sprawdzenia, czy plik istnieje, jest następujący:
import os
os.path.isfile('~/file.md') # Returns True if exists, else False
# additionaly check a dir
os.path.isdir('~/folder') # Returns True if the folder exists, else False
# check either a dir or a file
os.path.exists('~/file')
Zrobiłem wyczerpującą ściągę dla twojego odniesienia:
#os.path methods in exhaustive cheatsheet
{'definition': ['dirname',
'basename',
'abspath',
'relpath',
'commonpath',
'normpath',
'realpath'],
'operation': ['split', 'splitdrive', 'splitext',
'join', 'normcase'],
'compare': ['samefile', 'sameopenfile', 'samestat'],
'condition': ['isdir',
'isfile',
'exists',
'lexists'
'islink',
'isabs',
'ismount',],
'expand': ['expanduser',
'expandvars'],
'stat': ['getatime', 'getctime', 'getmtime',
'getsize']}
Jeśli plik jest przeznaczony do otwarcia, możesz użyć jednej z następujących technik:
with open('somefile', 'xt') as f: #Using the x-flag, Python3.3 and above
f.write('Hello\n')
if not os.path.exists('somefile'):
with open('somefile', 'wt') as f:
f.write("Hello\n")
else:
print('File already exists!')
AKTUALIZACJA
Aby uniknąć nieporozumień i na podstawie otrzymanych odpowiedzi, bieżąca odpowiedź znajduje plik lub katalog o podanej nazwie.
os.path.existszwraca true dla rzeczy, które nie są plikami, takich jak katalogi. To daje wyniki fałszywie pozytywne. Zobacz inne odpowiedzi, które zalecają os.path.isfile.
if os.path.isfile(path_to_file):
try:
open(path_to_file)
pass
except IOError as e:
print "Unable to open file"
Zgłaszanie wyjątków jest uważane za akceptowalne i Pythoniczne podejście do kontroli przepływu w twoim programie. Rozważ obsługę brakujących plików za pomocą IOErrors. W tej sytuacji wyjątek IOError zostanie zgłoszony, jeśli plik istnieje, ale użytkownik nie ma uprawnień do odczytu.
Możesz napisać sugestię Briana bez try:.
from contextlib import suppress
with suppress(IOError), open('filename'):
process()
suppressjest częścią Python 3.4. W starszych wersjach możesz szybko napisać własne pomijanie:
from contextlib import contextmanager
@contextmanager
def suppress(*exceptions):
try:
yield
except exceptions:
pass
Jestem autorem pakietu, który istnieje około 10 lat i ma funkcję, która bezpośrednio rozwiązuje to pytanie. Zasadniczo, jeśli korzystasz z systemu innego niż Windows, używa Popendostępu find. Jeśli jednak korzystasz z systemu Windows, replikuje się findza pomocą wydajnego systemu plików.
Sam kod nie używa trybloku… z wyjątkiem określania systemu operacyjnego i kierowania do stylu „Unix” findlub ręcznego buillta find. Testy czasowe wykazały, że tryszybsze było określanie systemu operacyjnego, więc użyłem jednego z nich (ale nigdzie indziej).
>>> import pox
>>> pox.find('*python*', type='file', root=pox.homedir(), recurse=False)
['/Users/mmckerns/.python']
A dokument…
>>> print pox.find.__doc__
find(patterns[,root,recurse,type]); Get path to a file or directory
patterns: name or partial name string of items to search for
root: path string of top-level directory to search
recurse: if True, recurse down from root directory
type: item filter; one of {None, file, dir, link, socket, block, char}
verbose: if True, be a little verbose about the search
On some OS, recursion can be specified by recursion depth (an integer).
patterns can be specified with basic pattern matching. Additionally,
multiple patterns can be specified by splitting patterns with a ';'
For example:
>>> find('pox*', root='..')
['/Users/foo/pox/pox', '/Users/foo/pox/scripts/pox_launcher.py']
>>> find('*shutils*;*init*')
['/Users/foo/pox/pox/shutils.py', '/Users/foo/pox/pox/__init__.py']
>>>
Wdrożenie, jeśli chcesz wyglądać, jest tutaj: https://github.com/uqfoundation/pox/blob/89f90fb308f285ca7a62eabe2c38acb87e89dad9/pox/shutils.py#L190
Możesz postępować zgodnie z tymi trzema sposobami:
Uwaga 1:
os.path.isfileUżywane tylko dla plików
import os.path
os.path.isfile(filename) # True if file exists
os.path.isfile(dirname) # False if directory exists
Uwaga 2:
os.path.existsUżywany zarówno dla plików, jak i katalogów
import os.path
os.path.exists(filename) # True if file exists
os.path.exists(dirname) #True if directory exists
pathlib.PathSposób (w Pythonie 3+ instalowane z pip Pythona 2)
from pathlib import Path
Path(filename).exists()
Dodanie jeszcze jednej niewielkiej zmiany, która nie jest dokładnie odzwierciedlona w innych odpowiedziach.
Zajmie się to przypadkiem file_pathistnienia Nonelub pustym ciągiem.
def file_exists(file_path):
if not file_path:
return False
elif not os.path.isfile(file_path):
return False
else:
return True
Dodanie wariantu na podstawie sugestii Shahbaz
def file_exists(file_path):
if not file_path:
return False
else:
return os.path.isfile(file_path)
Dodanie wariantu na podstawie sugestii Petera Wooda
def file_exists(file_path):
return file_path and os.path.isfile(file_path):
if (x) return true; else return false;jest naprawdę sprawiedliwy return x. Twoje cztery ostatnie linie mogą się stać return os.path.isfile(file_path). Skoro już o tym mowa, całą funkcję można uprościć jako return file_path and os.path.isfile(file_path).
return xw przypadku if (x). Python rozważy pusty ciąg Fałsz, w którym to przypadku zwracalibyśmy pusty ciąg zamiast bool. Celem tej funkcji jest zawsze zwracanie wartości bool.
xjest os.path.isfile(..)tak, że już bool.
os.path.isfile(None)podnosi wyjątek, dlatego dodałem czek if. Prawdopodobnie mógłbym to po prostu zawinąć w try / oprócz, ale czułem, że w ten sposób było to bardziej wyraźne.
return file_path and os.path.isfile(file_path)
Oto jedno wierszowe polecenie Python dla środowiska wiersza poleceń Linux. Uważam to za BARDZO HANDY, ponieważ nie jestem tak gorącym facetem Bash.
python -c "import os.path; print os.path.isfile('/path_to/file.xxx')"
Mam nadzieję, że to jest pomocne.
[ -f "${file}" ] && echo "file found" || echo "file not found"(to samo co if [ ... ]; then ...; else ...; fi).
Możesz użyć biblioteki „OS” Pythona:
>>> import os
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.txt")
True
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.tx")
False
os.path.existszwraca true dla rzeczy, które nie są plikami, takich jak katalogi. To daje wyniki fałszywie pozytywne. Zobacz inne odpowiedzi, które zalecają os.path.isfile.
existsjest w porządku. Jeśli celem jest ustalenie, czy bezpiecznie można otworzyć prawdopodobnie istniejący plik, wówczas krytyka jest uzasadniona i nie jest wystarczająco precyzyjna. Niestety OP nie określa, który cel jest pożądany (i prawdopodobnie już tego nie zrobi).
Jak sprawdzić, czy plik istnieje, bez użycia instrukcji try?
W 2016 r. Jest to prawdopodobnie najłatwiejszy sposób sprawdzenia, czy plik istnieje i czy jest to plik:
import os
os.path.isfile('./file.txt') # Returns True if exists, else False
isfilejest właściwie tylko metodą pomocniczą, która jest wewnętrznie używana os.stati stat.S_ISREG(mode)znajduje się pod spodem. Jest os.statto metoda niższego poziomu, która zapewni szczegółowe informacje o plikach, katalogach, gniazdach, buforach i innych. Więcej o os.stat tutaj
Uwaga: jednak to podejście nie blokuje pliku w żaden sposób, dlatego kod może stać się podatny na błędy związane z „ czasem sprawdzenia do czasu użycia ” ( TOCTTOU ).
Dlatego zgłaszanie wyjątków jest uważane za akceptowalne i Pythoniczne podejście do kontroli przepływu w twoim programie. I należy rozważyć obsługę brakujących plików za pomocą IOErrors, a nie ifinstrukcji ( tylko rada ).
import os.path
def isReadableFile(file_path, file_name):
full_path = file_path + "/" + file_name
try:
if not os.path.exists(file_path):
print "File path is invalid."
return False
elif not os.path.isfile(full_path):
print "File does not exist."
return False
elif not os.access(full_path, os.R_OK):
print "File cannot be read."
return False
else:
print "File can be read."
return True
except IOError as ex:
print "I/O error({0}): {1}".format(ex.errno, ex.strerror)
except Error as ex:
print "Error({0}): {1}".format(ex.errno, ex.strerror)
return False
#------------------------------------------------------
path = "/usr/khaled/documents/puzzles"
fileName = "puzzle_1.txt"
isReadableFile(path, fileName)
isReadableFile(path,fileName)zwróci, Truejeśli plik jest osiągalny i możliwy do odczytu przez proces \ program \ wątek