Як перевірити, чи існує файл чи ні, не використовуючи try
оператор?
Як перевірити, чи існує файл чи ні, не використовуючи try
оператор?
Відповіді:
Якщо ви перевіряєте причину, щоб ви могли зробити щось на кшталт if file_exists: open_it()
, безпечніше використовувати try
навколо спроби відкрити її. Перевірка, а потім відкриття ризикує видалити або перемістити файл або щось середнє, коли ви перевіряєте та намагаєтесь відкрити його.
Якщо ви не плануєте негайно відкривати файл, можете скористатися os.path.isfile
Повернення,
True
якщо шлях є існуючим звичайним файлом. З цього випливає символічне посилання, тому і islink (), і isfile () можуть бути істинними для одного шляху.
import os.path
os.path.isfile(fname)
якщо вам потрібно бути впевненим, що це файл.
Починаючи з Python 3.4, pathlib
модуль пропонує об'єктно-орієнтований підхід (підтримується на pathlib2
Python 2.7):
from pathlib import Path
my_file = Path("/path/to/file")
if my_file.is_file():
# file exists
Щоб перевірити каталог, виконайте:
if my_file.is_dir():
# directory exists
Щоб перевірити, чи Path
існує об'єкт незалежно від файлу чи каталогу, використовуйте exists()
:
if my_file.exists():
# path exists
Ви також можете використовувати resolve(strict=True)
в try
блоці:
try:
my_abs_path = my_file.resolve(strict=True)
except FileNotFoundError:
# doesn't exist
else:
# exists
FileNotFoundError
було введено в Python 3. Якщо ви також повинні підтримувати Python 2.7, а також Python 3, ви можете використовувати IOError
замість (які FileNotFoundError
підкласи) stackoverflow.com/a/21368457/1960959
open('file', 'r+')
), а потім прагнути до кінця.
Ви маєте os.path.exists
функцію:
import os.path
os.path.exists(file_path)
Це повертається True
як для файлів, так і для каталогів, але ви можете замість цього використовувати
os.path.isfile(file_path)
перевірити, чи це файл спеціально. З цього випливають символьні посилання.
На відміну від цього isfile()
, exists()
повернеться True
за каталогами. Тож залежно від того, чи потрібно лише звичайні файли, а також каталоги, ви будете використовувати isfile()
або exists()
. Ось простий вихід 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
Використовувати os.path.isfile()
з 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()
повернеться помилковим.
import os
, вам не потрібно import os.path
знову, оскільки це вже є частиною os
. Вам потрібно просто імпортувати, os.path
якщо ви збираєтесь використовувати лише функції з, os.path
а не від os
себе, щоб імпортувати дрібніші речі, але як ви використовуєте, так os.access
і os.R_OK
другий імпорт не потрібен.
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
Хоча майже всі можливі способи були перелічені у (принаймні одній із) існуючих відповідей (наприклад, додано конкретні матеріали Python 3.4 ), я спробую згрупувати все разом.
Примітка : кожен фрагмент стандартного коду бібліотеки Python, який я опублікую, належить до версії 3.5.3 .
Постановка проблеми :
Можливі рішення :
[Python 3]: os.path. існує ( шлях ) (також перевірити інші члени сім'ї функції , такі як os.path.isfile
, os.path.isdir
, os.path.lexists
для злегка різних поводжень)
os.path.exists(path)
Повернення,
True
якщо шлях посилається на існуючий шлях або відкритий дескриптор файлу. ПоверненняFalse
для розірваних символічних посилань. На деяких платформах ця функція може повернутися,False
якщо не буде надано дозвіл на виконання os.stat () на запитуваному файлі, навіть якщо шлях фізично існує.
Все добре, але якщо слідкувати за імпортом дерева:
os.path
- posixpath.py ( ntpath.py )
genericpath.py , рядок ~ # 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
це просто спробувати / крім блоку навколо [Python 3]: os. stat ( шлях, *, dir_fd = Немає, follow_symlinks = True ) . Отже, ваш код спробуйте / за винятком безкоштовного, але нижче в framestack є (принаймні) один такий блок. Це стосується і інших функцій (у тому числі os.path.isfile
).
1.1. [Пітон 3]: Шлях. is_file ()
Під капотом він робить саме те саме ( pathlib.py , рядок ~ # 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]: з менеджерами контексту заяви . Або:
Створіть:
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 ...)
І його використання - я повторюю свою os.path.isfile
поведінку (зауважте, що це лише для демонстраційних цілей, не намагайтеся написати такий код для виробництва ):
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
Використовуйте [Python 3]: contextlib. suppress ( * винятки ) - який був спеціально розроблений для вибіркового придушення винятків
Але вони, схоже, є обгортками над спробу / за винятком / else / нарешті блокує, як [Python 3]: у заяві вказано:
Це дозволяє звичайні спроби ... за винятком ..., нарешті, шаблони використання слід капсулювати для зручного використання.
Функції обходу файлової системи (і пошук результатів для відповідності предметів)
[Пітон 3]: ос. listdir ( path = '.' ) (або [Python 3]: os. scandir ( path = '.' ) на Python v 3.5 +, backport: [PyPI]: scandir )
Під кришкою обидва використовують:
через [GitHub]: python / cpython - (master) cpython / Модулі / posixmodule.c
Використання scandir () замість listdir () може значно підвищити продуктивність коду, який також потребує інформації про тип файлу чи атрибути файлів, оскільки об'єкти os.DirEntry розкривають цю інформацію, якщо операційна система надає її під час сканування каталогу. Усі методи os.DirEntry можуть виконувати системний виклик, але is_dir () та is_file () зазвичай вимагають лише системного виклику для символічних посилань; os.DirEntry.stat () завжди вимагає системного виклику в Unix, але вимагає лише одного для символічних посилань у Windows.
os.listdir
( os.scandir
коли є)glob.glob
)
os.listdir
Так як ці ітерації по папках, (в більшості випадків) вони неефективні для нашої задачі (є винятки, наприклад , не символ підстановки Глоб Бінг - в @ShadowRanger вказував), так що я не буду наполягати на них. Не кажучи вже про те, що в деяких випадках може знадобитися обробка імені файлів.
[Пітон 3]: ос. доступ ( шлях, режим, *, dir_fd = Немає, эффективен_ids = Неправдивий, follow_symlinks = True ) , поведінка якого близька os.path.exists
(насправді вона ширша, головним чином через 2- й аргумент)
... перевірити, чи користувач, що викликає, має вказаний доступ до шляху . режим повинен бути F_OK для перевірки існування шляху ...
os.access("/tmp", os.F_OK)
Оскільки я також працюю в C , я також використовую цей метод, тому що під кришкою він викликає нативні API s (знову ж таки, через "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c" ), але він також відкриває ворота для можливого користувача помилки , і це не так Python ic, як інші варіанти. Отже, як справедливо зазначав @AaronHall, не використовуйте його, якщо ви не знаєте, що робите:
Примітка : виклик рідних API s також можливий через [Python 3]: ctypes - Бібліотека іноземних функцій для Python , але в більшості випадків це складніше.
( Win конкретно): Оскільки vcruntime * ( msvcr * ) .dll експортує [MS.Docs]: _access, сімейство функцій _waccess , ось ось приклад:
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
Примітки :
os.F_OK
в дзвінку, але це просто для ясності (його значення дорівнює 0 )
Також аналог 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
Примітки :
Натомість шлях жорсткого кодування libc ( "/lib/x86_64-linux-gnu/libc.so.6" ), який може (і, швидше за все, буде) змінюватись в різних системах, жодна (або порожня рядок) не може бути передана конструктору CDLL ( ctypes.CDLL(None).access(b"/tmp", os.F_OK)
). Відповідно до [man7]: DLOPEN (3) :
Якщо ім'я файлу NULL, то повертається ручка призначена для основної програми. Якщо дано dlsym (), ця ручка викликає пошук символу в основній програмі, після чого всі спільні об'єкти, завантажені при запуску програми, а потім усі спільні об'єкти, завантажені dlopen () з прапором RTLD_GLOBAL .
__declspec(dllexport)
(чому на Землі звичайна людина зробила б це?), основна програма завантажена, але майже непридатнаВстановіть якийсь сторонній модуль із можливостями файлової системи
Швидше за все, буде покладатися на один із способів, описаних вище (можливо, з невеликими налаштуваннями).
Одним із прикладів може бути (знову ж таки, Win конкретно) [GitHub]: mhammond / pywin32 - розширення Python для Windows (pywin32) , що є обгорткою Python для WINAPI .
Але, оскільки це більше схоже на вирішення проблеми, я зупиняюся тут.
Інший (кульгавий) спосіб вирішення ( gainarie ) - це (як я це люблю називати), підхід sysadmin : використовувати Python як обгортку для виконання команд оболонки
Виграти :
(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
Підсумок :
Заключна примітка :
glob.iglob
(і glob.glob
так само) базуєтьсяos.scandir
, тому зараз лінь; щоб отримати перше звернення до каталогу файлів 10M, ви скануєте лише до першого звернення. І навіть до 3.6, якщо ви використовуєте glob
методи без будь-яких символів, ця функція є розумною: вона знає, що ви можете мати лише один удар, тому вона спрощує глобалізацію до справедливої os.path.isdir
абоos.path.lexists
(залежно від того, чи закінчується шлях /
).
os.path.isdir
або os.path.lexist
оскільки це купа викликів і рядків функції рівня Python Операції до того, як він вирішить, ефективний шлях є життєздатним, але немає додаткового системного виклику або роботи вводу / виводу, що на порядок повільніше).
Це найпростіший спосіб перевірити наявність файлу. Тільки тому, що файл існував під час перевірки, не гарантує, що він буде там, коли потрібно його відкрити.
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+ є об'єктно-орієнтований модуль шляху: pathlib . За допомогою цього нового модуля ви можете перевірити, чи існує такий файл:
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
Ви можете (і зазвичай слід) використовувати try/except
блок під час відкриття файлів:
try:
with p.open() as f:
# do awesome stuff
except OSError:
print('Well darn.')
Модуль pathlib містить у собі багато цікавих матеріалів: зручне глобулювання, перевірка власника файлу, просте приєднання шляху тощо. Варто перевірити. Якщо ви перебуваєте на більш старій версії Python (версія 2.6 або пізніша версія), ви все одно можете встановити pathlib за допомогою pip:
# installs pathlib2 on older Python versions
# the original third-party module, pathlib, is no longer maintained.
pip install pathlib2
Потім імпортуйте його наступним чином:
# Older Python versions
import pathlib2 as pathlib
Віддайте перевагу оператору спробу. Це вважається кращим стилем і уникає перегонів.
Не сприймайте мого слова за це. Існує велика підтримка цієї теорії. Ось пара:
try...except
жодного разу не допомагає вирішити цю проблему.
except:
застереження призведе до того, що виняток, що виникає в цій частині вашого коду, призведе до заплутаного повідомлення (друга помилка, піднята під час обробка першого.)
Як перевірити, чи існує файл, використовуючи Python, не використовуючи оператор спробу?
Тепер, починаючи з Python 3.4, можна імпортувати та інстанціювати Path
об’єкт з ім'ям файлу та перевірити is_file
метод (зауважте, що це повертає True для символьних посилань, що вказують і на звичайні файли):
>>> from pathlib import Path
>>> Path('/').is_file()
False
>>> Path('/initrd.img').is_file()
True
>>> Path('/doesnotexist').is_file()
False
Якщо ви перебуваєте на Python 2, ви можете підтримати модуль pathlib з pypi pathlib2
, або іншим чином перевірити його isfile
з os.path
модуля:
>>> import os
>>> os.path.isfile('/')
False
>>> os.path.isfile('/initrd.img')
True
>>> os.path.isfile('/doesnotexist')
False
Тепер вищесказане, мабуть, найкращий прагматичний прямий відповідь тут, але є можливість перегонового стану (залежно від того, що ви намагаєтеся виконати), а також те, що в основі лежить реалізація try
, але Python використовує try
всюди в своїй реалізації.
Оскільки Python використовується try
скрізь, насправді немає причин уникати реалізації, яка використовує його.
Але решта цієї відповіді намагається розглянути ці застереження.
Доступний з Python 3.4, використовуйте новий Path
об'єкт у pathlib
. Зауважте, що .exists
це не зовсім правильно, оскільки каталоги - це не файли (за винятком сенсу, що все є файлом).
>>> from pathlib import Path
>>> root = Path('/')
>>> root.exists()
True
Тому нам потрібно використовувати is_file
:
>>> root.is_file()
False
Ось допомога на тему is_file
:
is_file(self)
Whether this path is a regular file (also True for symlinks pointing
to regular files).
Тож давайте отримаємо файл, про який ми знаємо, що це файл:
>>> import tempfile
>>> file = tempfile.NamedTemporaryFile()
>>> filepathobj = Path(file.name)
>>> filepathobj.is_file()
True
>>> filepathobj.exists()
True
За замовчуванням NamedTemporaryFile
видаляє файл, коли він закритий (і автоматично закриється, коли на нього більше не існує посилань).
>>> del file
>>> filepathobj.exists()
False
>>> filepathobj.is_file()
False
Якщо ви скористаєтеся реалізацією , ви побачите, що is_file
використовується 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
Нам це подобається, try
тому що він уникає перегонів. З try
, ви просто намагаєтеся прочитати файл, чекаючи , що вона буде там, і якщо немає, то зловити виняток і виконати всі , що Відкат поведінка має сенс.
Якщо ви хочете перевірити, чи існує файл, перш ніж спробувати його прочитати, і ви можете його видалити, а потім ви можете використовувати кілька потоків або процесів, або інша програма знає про цей файл і може видалити його - ви ризикуєте отримати шанс стан гонки , якщо перевірити його існує, тому що ви тоді мчить , щоб відкрити його до свого стану (його існування) змінюється.
Умови гонки дуже важко налагодити, тому що є дуже маленьке вікно, в якому вони можуть спричинити збій вашої програми.
Але якщо це ваша мотивація, ви можете отримати значення atry
твердження за допомогою suppress
менеджера контексту.
suppress
Python 3.4 дає нам suppress
менеджер контексту (раніше ignore
менеджер контексту), який робить семантично абсолютно те саме в меншій кількості рядків, а також (принаймні поверхово) зустрічаючись з оригіналом, просить уникнути try
заяви:
from contextlib import suppress
from pathlib import Path
Використання:
>>> with suppress(OSError), Path('doesnotexist').open() as f:
... for line in f:
... print(line)
...
>>>
>>> with suppress(OSError):
... Path('doesnotexist').unlink()
...
>>>
Для більш ранніх пітонів ви могли розгорнути свій власний suppress
, але без try
заповіту буде більш багатослівним, ніж з. Я вважаю, що це насправді єдина відповідь, яка не використовується try
на будь-якому рівні в Python, до якої можна застосувати до Python 3.4, оскільки замість цього використовується менеджер контексту:
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)
Можливо, простіше: спробуйте:
from contextlib import contextmanager
@contextmanager
def suppress(*exceptions):
try:
yield
except exceptions:
pass
isfile
import os
os.path.isfile(path)
з документів :
os.path.isfile(path)
Повернути True, якщо шлях є існуючим звичайним файлом. Звідси випливає символічне посилання, тому і
islink()
іisfile()
може бути правдою для одного шляху.
Але якщо вивчити джерело цієї функції, ви побачите, що вона насправді використовує спробуйте:
# 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
Все, що він робить, - це використовувати заданий шлях, щоб побачити, чи може він отримати статистику по ньому, ловити OSError
та перевіривши, чи це файл, якщо він не підняв виняток.
Якщо ви збираєтесь зробити щось із файлом, я б запропонував безпосередньо спробувати його, за винятком випадків, щоб уникнути перегонів:
try:
with open(path) as f:
f.read()
except OSError:
pass
ос.доступ
Доступно для Unix і Windows є os.access
, але для їх використання потрібно передавати прапори, і це не розрізняє файли та каталоги. Це більше використовується для перевірки, чи справжній користувач, що викликає доступ, має доступ у середовищі підвищених привілеїв:
import os
os.access(path, os.F_OK)
Він також страждає від тих же проблем зі станом раси, що і isfile
. З документів :
Примітка: Використання доступу () для перевірки того, чи користувач має право, наприклад, відкривати файл, перш ніж це зробити, використовуючи open (), створює отвір у захисті, оскільки користувач може використовувати короткий проміжок часу між перевіркою та відкриттям файлу для маніпулювання ним. Переважно використовувати методи EAFP. Наприклад:
if os.access("myfile", os.R_OK): with open("myfile") as fp: return fp.read() return "some default data"
краще писати так:
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()
Уникайте використання os.access
. Це функція низького рівня, яка має більше можливостей для помилок користувача, ніж обговорювані вище об'єкти та функції.
Ще одна відповідь говорить про це os.access
:
Особисто я віддаю перевагу цьому, тому що під кришкою він називає нативні API (через "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), але він також відкриває ворота для можливих помилок користувача, і це не так Pythonic, як інші варіанти :
У цій відповіді сказано, що він надає перевагу непітонічному методу, схильному до помилок, без виправдання. Здається, це заохочує користувачів використовувати API низького рівня, не розуміючи їх.
Він також створює контекстний менеджер, який, безумовно, повертаючись True
, дозволяє всі винятки (включаючи KeyboardInterrupt
іSystemExit
!) Пройти безшумно, що є хорошим способом приховати помилки.
Це, мабуть, спонукає користувачів до прийняття поганої практики.
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!"
Імпорт os
полегшує навігацію та виконання стандартних дій із операційною системою.
Для ознайомлення також див. Як перевірити, чи існує файл за допомогою Python?
Якщо вам потрібні операції високого рівня, використовуйте shutil
.
os.path.exists
повертає true для речей, які не є файлами, наприклад, каталогів. Це дає помилкові позитиви. Дивіться інші відповіді, які рекомендують os.path.isfile
.
Тестування файлів і папок з os.path.isfile()
, os.path.isdir()
іos.path.exists()
Припускаючи, що "шлях" є дійсним шляхом, у цій таблиці показано, що повертається кожною функцією для файлів і папок:
Ви також можете перевірити, чи файл - це певний тип файлів, використовуючи os.path.splitext()
для отримання розширення (якщо ви цього ще не знаєте)
>>> 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
У 2016 році найкращий спосіб все ще використовується os.path.isfile
:
>>> os.path.isfile('/path/to/some/file.txt')
Або в Python 3 ви можете використовувати pathlib
:
import pathlib
path = pathlib.Path('/path/to/some/file.txt')
if path.is_file():
...
pathlib
є рішенням OOP python для шляхів. З цим можна зробити набагато більше. Якщо вам просто потрібно перевірити існування, перевага не така велика.
Мабуть, не існує змістовної функціональної різниці між спробою / за винятком і isfile()
, тому слід використовувати те, що має сенс.
Якщо ви хочете прочитати файл, якщо він існує, зробіть це
try:
f = open(filepath)
except IOError:
print 'Oh dear.'
Але якщо ви просто хотіли перейменувати файл, якщо він існує, і тому його не потрібно відкривати, зробіть це
if os.path.isfile(filepath):
os.rename(filepath, filepath + '.old')
Якщо ви хочете записати у файл, якщо він не існує, зробіть це
# 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'
Якщо вам потрібно заблокувати файл, це вже інша справа.
os.path.exists
повертає true для речей, які не є файлами, наприклад, каталогів. Це дає помилкові позитиви. Дивіться інші відповіді, які рекомендують os.path.isfile
.
filepath
правильним часом, і BAM , ви перезаписуєте цільовий файл. Ви повинні робити open(filepath, 'wx')
це try...except
блоком, щоб уникнути проблеми.
OSError
якщо він filepath + '.old'
вже існує: "У Windows, якщо dst вже існує, OSError буде піднятий, навіть якщо це файл; можливо, немає можливості реалізувати атомну перейменування, коли dst називає існуючий файл. "
os.replace
портативно виконує безшумну заміну файлу призначення (він ідентичний os.rename
поведінці Linux) (він помиляється лише в тому випадку, якщо ім'я призначення є і є каталогом). Таким чином, ви застрягли на 2.x, але користувачі Py3 мали хороший варіант вже кілька років.
rename
прикладі: все одно це слід робити з try
/ except
. os.rename
(або os.replace
на сучасному Python) є атомним; перевіряючи, тоді перейменування вводить непотрібну гонку та додаткові системні виклики. Просто зробітьtry: os.replace(filepath, filepath + '.old') except OSError: pass
Ви можете спробувати це (безпечніше):
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))
Вихід буде:
([Errno 2] Немає такого файлу чи каталогу: "будь-який.txt")
Тоді, залежно від результату, ваша програма може просто продовжувати працювати звідти, або ви можете ввести код, щоб зупинити її, якщо хочете.
try
Хоча я завжди рекомендую використовувати try
та except
заяви, але для вас є декілька можливостей (моя особиста фаворитка - це використання os.access
):
Спробуйте відкрити файл:
Відкриття файлу завжди підтвердить існування файлу. Ви можете зробити функцію так само:
def File_Existence(filepath):
f = open(filepath)
return True
Якщо це False, він зупинить виконання з безмежною IOError або OSError в пізніших версіях Python. Щоб зловити виняток, вам потрібно використати спробу, за винятком пункту. Звичайно, ви завжди можете використовувати за try
винятком оператора `if '(завдяки hsandt
за те, що я задумався):
def File_Existence(filepath):
try:
f = open(filepath)
except IOError, OSError: # Note OSError is for later versions of Python
return False
return True
Використання os.path.exists(path)
:
Це дозволить перевірити існування того, що ви вказали. Однак він перевіряє наявність файлів та каталогів, тому будьте обережні, як ви ним користуєтесь.
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
Використання os.access(path, mode)
:
Це дозволить перевірити, чи є у вас доступ до файлу. Він перевірить наявність дозволів. На основі документації на os.py, ввівши os.F_OK
її, вона перевірить існування шляху. Однак, використовуючи це, ви створите отвір у захисті, оскільки хтось може атакувати ваш файл, використовуючи час між перевіркою дозволів та відкриттям файлу. Натомість слід перейти безпосередньо до відкриття файлу, а не перевіряти його дозволи. ( EAFP проти LBYP ). Якщо ви не збираєтеся потім відкривати файл і лише перевіряти його існування, ви можете скористатися цим.
У будь-якому випадку, тут:
>>> import os
>>> os.access("/is/a/file.txt", os.F_OK)
True
Я також повинен зазначити, що є два способи, за якими ви не зможете перевірити існування файлу. Або питання буде, permission denied
або no such file or directory
. Якщо ви ловите IOError
, встановіть IOError as e
(як, наприклад, мій перший варіант) та введіть текст, print(e.args)
щоб можна було сподіватися визначити свою проблему. Я сподіваюся, що це допомагає! :)
Дата: 2017-12-04
Кожне можливе рішення було перелічено в інших відповідях.
Інтуїтивно зрозумілий і аргументований спосіб перевірити наявність файлу є наступним:
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')
Я зробив вичерпний чіт-лист для вашої довідки:
#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']}
Якщо файл призначений для відкриття, ви можете скористатися однією з таких методик:
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!')
ОНОВЛЕННЯ
Тільки, щоб уникнути плутанини та на основі отриманих відповідей, поточна відповідь знаходить або файл, або каталог із заданим іменем.
os.path.exists
повертає true для речей, які не є файлами, наприклад, каталогів. Це дає помилкові позитиви. Дивіться інші відповіді, які рекомендують 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"
Збільшення винятків вважається прийнятним та пітонічним підходом до контролю потоку у вашій програмі. Подумайте про обробку відсутніх файлів за допомогою IOErrors. У цій ситуації виняток IOError буде піднято, якщо файл існує, але користувач не має дозволів на читання.
Можна написати пропозицію Брайана без цього try:
.
from contextlib import suppress
with suppress(IOError), open('filename'):
process()
suppress
є частиною Python 3.4. У старих випусках ви можете швидко написати власне подавлення:
from contextlib import contextmanager
@contextmanager
def suppress(*exceptions):
try:
yield
except exceptions:
pass
Я автор пакету, який існує близько 10 років, і він має функцію, яка безпосередньо стосується цього питання. В основному, якщо ви працюєте в системі, яка не є системою Windows, вона використовує Popen
для доступу find
. Однак якщо ви працюєте в Windows, він реплікується find
за допомогою ефективної прогулки файлової системи.
Сам код не використовує try
блок… за винятком визначення операційної системи і, таким чином, керування вами до стилю «Unix» find
або hand-buillt find
. Тести на встановлення термінів показали, що try
швидкість у визначенні ОС була швидшою, тому я там її застосував (але більше ніде).
>>> import pox
>>> pox.find('*python*', type='file', root=pox.homedir(), recurse=False)
['/Users/mmckerns/.python']
І док ...
>>> 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']
>>>
Реалізація, якщо ви хочете подивитися, тут: https://github.com/uqfoundation/pox/blob/89f90fb308f285ca7a62eabe2c38acb87e89dad9/pox/shutils.py#L190
Ви можете дотримуватися цих трьох способів:
Примітка1:
os.path.isfile
використовується лише для файлів
import os.path
os.path.isfile(filename) # True if file exists
os.path.isfile(dirname) # False if directory exists
Примітка2:
os.path.exists
використовується як для файлів, так і для каталогів
import os.path
os.path.exists(filename) # True if file exists
os.path.exists(dirname) #True if directory exists
pathlib.Path
Метод (включено в Python 3 +, що встановлюється з Піп для Python 2)
from pathlib import Path
Path(filename).exists()
Додаємо ще одну незначну варіацію, яка не відображена точно в інших відповідях.
Це стосується випадку file_path
буття None
або порожнього рядка.
def file_exists(file_path):
if not file_path:
return False
elif not os.path.isfile(file_path):
return False
else:
return True
Додавання варіанту на основі пропозиції Шахбаза
def file_exists(file_path):
if not file_path:
return False
else:
return os.path.isfile(file_path)
Додавання варіанту на основі пропозиції Пітера Вуда
def file_exists(file_path):
return file_path and os.path.isfile(file_path):
if (x) return true; else return false;
насправді просто return x
. Вашими останніми чотирма рядками можуть стати return os.path.isfile(file_path)
. Поки ми працюємо, всю функцію можна спростити як return file_path and os.path.isfile(file_path)
.
return x
у випадку if (x)
. Python вважатиме порожню рядок False, і в цьому випадку ми повертаємо порожню рядок замість bool. Мета цієї функції - завжди повертати bool.
x
це os.path.isfile(..)
так уже BOOL.
os.path.isfile(None)
викликає виняток, тому я додав прапорець if. Я, ймовірно, міг би просто загорнути його в спробу / крім цього, але я вважав, що це було більш чітко.
return file_path and os.path.isfile(file_path)
Ось команда Python на 1 рядок для середовища командного рядка Linux. Я знаходжу це ДУЖЕ РОЧУ, оскільки я не такий гарячий хлопець Баша.
python -c "import os.path; print os.path.isfile('/path_to/file.xxx')"
Я сподіваюся, що це корисно.
[ -f "${file}" ] && echo "file found" || echo "file not found"
(що таке саме if [ ... ]; then ...; else ...; fi
).
Ви можете використовувати бібліотеку "ОС" Python:
>>> import os
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.txt")
True
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.tx")
False
os.path.exists
повертає true для речей, які не є файлами, наприклад, каталогів. Це дає помилкові позитиви. Дивіться інші відповіді, які рекомендують os.path.isfile
.
exists
це добре. Якщо мета - визначити, чи безпечно відкрити імовірно існуючий файл, то критика виправдана і існує недостатньо точно. На жаль, ОП не вказує, яка є бажана мета (і, мабуть, більше не зробить цього).
Як перевірити, чи існує файл, не використовуючи оператор спробу?
У 2016 році це, мабуть, найпростіший спосіб перевірити, чи існує обидва файли та чи є він файлом:
import os
os.path.isfile('./file.txt') # Returns True if exists, else False
isfile
насправді є лише допоміжним методом, який використовується внутрішньо os.stat
і stat.S_ISREG(mode)
під ним. Це os.stat
метод нижчого рівня, який надасть вам детальну інформацію про файли, каталоги, сокети, буфери тощо. Більше про os.stat тут
Примітка: Однак такий підхід жодним чином не заблокує файл, і тому ваш код може стати вразливим до помилок " час перевірки на час використання " ( TOCTTOU ).
Тому підвищення винятків вважається прийнятним та пітонічним підходом до контролю потоку у вашій програмі. І слід розглянути питання про обробку відсутніх файлів за допомогою IOErrors, а не if
твердження ( лише порада ).
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)
повернеться, True
якщо файл буде доступний і