Jak sprawdzić, czy plik istnieje, czy nie, bez użycia try
instrukcji?
Jak sprawdzić, czy plik istnieje, czy nie, bez użycia try
instrukcji?
Odpowiedzi:
Jeśli sprawdzasz, że możesz zrobić coś takiego if file_exists: open_it()
, bezpieczniej jest skorzystać try
z 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óć,
True
jeś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, pathlib
moduł oferuje podejście obiektowe (przeniesione do pathlib2
Pythona 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 Path
obiekt 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 try
bloku:
try:
my_abs_path = my_file.resolve(strict=True)
except FileNotFoundError:
# doesn't exist
else:
# exists
FileNotFoundError
został wprowadzony w Pythonie 3. Jeśli potrzebujesz także obsługiwać Python 2.7 oraz Python 3, możesz IOError
zamiast tego użyć (które FileNotFoundError
podklasy) stackoverflow.com/a/21368457/1960959
open('file', 'r+')
), a następnie przejść do końca.
Masz os.path.exists
funkcję:
import os.path
os.path.exists(file_path)
Zwraca True
zaró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 True
po 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 os
musisz tego robić, import os.path
ponieważ jest to już część os
. Musisz tylko zaimportować, os.path
jeśli zamierzasz używać funkcji z siebie, os.path
a nie od os
siebie, aby zaimportować mniejszą rzecz, ale podczas używania os.access
i os.R_OK
drugi 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.lexists
dla nieco odmiennych zachowań)
os.path.exists(path)
Zwraca,
True
jeśli ścieżka odnosi się do istniejącej ścieżki lub otwartego deskryptora pliku. ZwracaFalse
za zepsute dowiązania symboliczne. Na niektórych platformach funkcja ta może zwrócić,False
jeś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 True
to 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.isfile
zachowanie (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 result
Uż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.scandir
gdy 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_OK
tego 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.glob
ró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 glob
metod bez symboli wieloznacznych, funkcja jest inteligentna: wie, że możesz mieć tylko jedno trafienie, więc upraszcza globowanie tylko doos.path.isdir
os.path.lexists
( lub w zależności od tego, czy ścieżka się kończy /
).
os.path.isdir
lub os.path.lexist
ponieważ 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/except
bloku 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...except
tak 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ę Path
obiektu o nazwie pliku, i sprawdź is_file
metodę (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 pathlib2
lub w inny sposób sprawdzić isfile
z os.path
moduł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 try
wszędzie w swojej implementacji.
Ponieważ Python używa try
wszę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 Path
obiektu w pathlib
. Zauważ, że .exists
to 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 NamedTemporaryFile
usuwa 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_file
uż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, try
ponieważ pozwala uniknąć warunków wyścigowych. Dzięki try
po 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ść try
rachunku za pomocą suppress
menedżera kontekstowe.
suppress
Python 3.4 udostępnia nam suppress
menedżera kontekstu (wcześniej ignore
menedż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 try
instrukcji:
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 try
będzie bardziej gadatliwy niż z. Wierzę, że tak naprawdę jest to jedyna odpowiedź, która nie jest używana try
na ż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, OSError
a 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 True
pozwala wszystkim wyjątkom (w tym KeyboardInterrupt
i 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 os
uł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.exists
zwraca 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():
...
pathlib
jest 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.exists
zwraca 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
.
filepath
odpowiednim czasie, a BAM zastępujesz plik docelowy. Powinieneś zrobić open(filepath, 'wx')
w try...except
bloku, aby uniknąć problemu.
OSError
jeś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.rename
zachowaniem 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.
rename
przykładzie: należy to zrobić za pomocą try
/ except
. os.rename
(lub os.replace
na 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 try
i except
oś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ć try
instrukcji 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 True
Uż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")
False
Uż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)
True
Powinienem także wspomnieć, że istnieją dwa sposoby, aby nie można było zweryfikować istnienia pliku. Albo będzie to problem, permission denied
albo 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.exists
zwraca 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()
suppress
jest 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 Popen
dostępu find
. Jeśli jednak korzystasz z systemu Windows, replikuje się find
za pomocą wydajnego systemu plików.
Sam kod nie używa try
bloku… z wyjątkiem określania systemu operacyjnego i kierowania do stylu „Unix” find
lub ręcznego buillta find
. Testy czasowe wykazały, że try
szybsze 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.isfile
Uż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.exists
Uż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.Path
Sposó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_path
istnienia None
lub 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 x
w 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.
x
jest 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.exists
zwraca 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
.
exists
jest 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
isfile
jest właściwie tylko metodą pomocniczą, która jest wewnętrznie używana os.stat
i stat.S_ISREG(mode)
znajduje się pod spodem. Jest os.stat
to 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 if
instrukcji ( 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, True
jeśli plik jest osiągalny i możliwy do odczytu przez proces \ program \ wątek