Как мне проверить, существует ли файл, без использования оператора try?

6484
spence91 17 Сен 2008 в 16:55
1
Похоже, это классическое обсуждение EAFP и LBYL, см., Например, этот связанный вопрос: stackoverflow.com/questions/ 1835756 / using-try-vs-if-in-python
 – 
matth
30 Окт 2019 в 11:20

30 ответов

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
282
Peter Mortensen 2 Июн 2018 в 23:52
Как правило, не рекомендуется называть переменные такими же, как имена методов.
 – 
Homunculus Reticulli
3 Апр 2020 в 20:10

Хотя почти все возможные способы были перечислены в (по крайней мере, в одном из) существующих ответов (например, был добавлен конкретный материал для Python 3.4 ), я постараюсь сгруппировать все вместе.

Примечание : каждый фрагмент кода стандартной библиотеки Python , который я собираюсь опубликовать, принадлежит версии 3.5.3 .

Описание проблемы :

  1. Проверить наличие файла ( спорного : также папки ("особого" файла)?)
  2. Не используйте try / except / else / finally блоки

Возможные решения :

  1. [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 (путь):      "" "Проверить, существует ли путь. Возвращает False для неработающих символических ссылок" ""      пытаться:          st = os.stat (путь)      кроме os.error:          вернуть ложь      вернуть True   

    это просто блок try / except вокруг [Python 3]: os. stat ( путь, *, dir_fd = None, follow_symlinks = True < / em>). Итак, ваш код попробуйте / за исключением бесплатен, но ниже в стеке кадров есть (по крайней мере) один такой блок. Это также относится к другим функциям ( включая os.path.isfile).

    1.1. [Python 3]: путь. is_file ()

    • Это более изящный (и более python ic) способ обработки путей, но
    • Под капотом он делает в точности то же самое ( pathlib.py , строка ~ # 1330 ):

        def is_file (self):      "" "      Является ли этот путь обычным файлом (также True для символических ссылок, указывающих      в обычные файлы).      "" "      пытаться:          вернуть S_ISREG (self.stat (). st_mode)      кроме OSError как e:          если e.errno отсутствует в (ENOENT, ENOTDIR):              поднимать          # Путь не существует или символическая ссылка не работает          # (см. https://bitbucket.org/pitrou/pathlib/issue/12/)          вернуть ложь   
  2. [Python 3]: с менеджерами контекста операторов. Или:

    • Создать:

        class Swallow: # Пустой пример      swallowed_exceptions = (FileNotFoundError,)       def __enter __ (сам):          print ("Вход ...")       def __exit __ (self, exc_type, exc_value, exc_traceback):          print ("Выход:", exc_type, exc_value, exc_traceback)          return exc_type в Swallow.swallowed_exceptions # только проглатывать FileNotFoundError (не, например, TypeError - если пользователь передает неверный аргумент, например None или float или ...)   
      • И его использование - я воспроизведу поведение os.path.isfile (обратите внимание, что это просто для демонстрации, не пытайтесь написать такой код для производственной ):

          импорт ОС  статистика импорта    def isfile_seaman (путь): # Dummy func      результат = Ложь      с Swallow ():          результат = stat.S_ISREG (os.stat (путь) .st_mode)      вернуть результат   
    • Используйте [Python 3]: contextlib. подавить ( * исключения ) - который был специально разработан для выборочного подавления исключений


    Но они кажутся обертками над попыткой / за исключением / else / finally блокируется как [Python 3]: в инструкции with говорится:

    Это позволяет обычно попробовать... except... finally шаблоны использования, которые необходимо инкапсулировать для удобного повторного использования.

  3. Функции обхода файловой системы (и поиск в результатах соответствующих элементов)


    Поскольку они перебирают папки (в большинстве случаев), они неэффективны для нашей проблемы (есть исключения, такие как glob bing без подстановочных знаков - как указал @ShadowRanger), поэтому я Я не собираюсь на них настаивать. Не говоря уже о том, что в некоторых случаях может потребоваться обработка имени файла.

  4. [Python 3]: os. доступ (< em> path, mode, *, dir_fd = None, effective_ids = False, follow_symlinks = True ), поведение которого близко к os.path.exists (на самом деле оно шире, в основном из-за 2 nd аргумент)

    • разрешения пользователя могут ограничивать "видимость" файла, как указано в документе: <цитата>

      ... проверить, имеет ли вызывающий пользователь указанный доступ к пути . режим должен быть F_OK для тестирования наличие пути ...

    os.access("/tmp", os.F_OK)

    Поскольку я также работаю на C , я также использую этот метод, потому что внутри он вызывает собственные API (опять же, через "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c" ), но он также открывает ворота для возможных ошибок пользователя , а не как Python ic как и другие варианты. Итак, как справедливо заметил @AaronHall, не используйте его, если не знаете, что делаете:

    Примечание : вызов собственных API также возможен через [Python 3]: ctypes - библиотека сторонних функций для Python, но в большинстве случаев она более сложная.

    ( Win ): поскольку vcruntime * ( msvcr * ) .dll экспортирует a [MS.Docs ]: _access, _waccess, а также семейство функций, вот пример:

      Python 3.5.3 (v3.5.3: 1880cb95a742, 16 января 2017 г., 16:02:32) [MSC v.1900, 64 бит (AMD64)] на win32  Для получения дополнительной информации введите «помощь», «авторские права», «кредиты» или «лицензия».  >>> 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 )
    • Я использую _waccess , чтобы один и тот же код работал на Python3 и Python2 (несмотря на unicode связанные различия между ними)
    • Хотя это нацелено на очень конкретную область, об этом не упоминалось ни в одном из предыдущих ответов


    Аналог Lnx ( Ubtu (16 x64) ):

      Python 3.5.2 (по умолчанию, 17 ноября 2016 г., 17:05:23)  [GCC 5.4.0 20160609] в Linux  Для получения дополнительной информации введите «помощь», «авторские права», «кредиты» или «лицензия».  >>> 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): <цитата>

      Если filename имеет значение NULL, то возвращаемый дескриптор предназначен для основного программа. При передаче dlsym () этот дескриптор вызывает поиск символ в основной программе, за которым следуют все общие объекты, загруженные в запуск программы, а затем все общие объекты, загруженные dlopen () с флаг RTLD_GLOBAL .

      • Основная (текущая) программа ( python ) связана с libc , поэтому ее символы (включая доступ ) будут загружены
      • С этим нужно обращаться осторожно, поскольку доступны такие функции, как main , Py_Main и (все) другие; их вызов может иметь катастрофические последствия (для текущей программы)
      • Это также не относится к Win (но это не такая уж большая проблема, поскольку msvcrt.dll находится в "% SystemRoot% \ System32 ", который по умолчанию находится в % PATH% ). Я хотел пойти дальше и воспроизвести это поведение на Win (и отправить исправление), но, как оказалось, [MS.Docs]: функция GetProcAddress" видит "только экспортированные символы, поэтому, если кто-то объявляет функции в основном исполняемом файле как __declspec(dllexport) (почему, черт возьми, это делает обычный человек?), основная программа загружается, но в значительной степени непригодна для использования
  5. Установите сторонний модуль с возможностями файловой системы

    Скорее всего, будет полагаться на один из способов, описанных выше (возможно, с небольшими настройками).
    Одним из примеров может быть (опять же, для Win ) [GitHub]: mhammond / pywin32 - Python для Windows (pywin32) Extensions, который является оболочкой Python над WINAPI .

    Но, поскольку это больше похоже на обходной путь, я останавливаюсь на этом.

  6. Другой (неубедительный) обходной путь ( 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   

Итог :

  • Используйте try / except / else / finally , потому что они могут предотвратить ряд неприятных проблем. Противоположным примером, который я могу придумать, является производительность: такие блоки являются дорогостоящими, поэтому старайтесь не помещать их в код, который должен запускаться сотни тысяч раз в секунду (но поскольку (в большинстве случаев) это связано с доступом к диску, это не так).

Заключительные примечания :

  • Я постараюсь поддерживать его в актуальном состоянии, любые предложения приветствуются, я включу все полезное, что появится в ответе
244
CristiFati 8 Фев 2019 в 12:36
3
Вы можете уточнить это заявление? «Хотя это не очень хорошая практика, я использую в вызове os.F_OK, но это просто для ясности (его значение равно 0)»
 – 
sk8asd123
19 Ноя 2017 в 04:46
6
@ sk8asd123: Трудно обдумать это в комментарии: как правило, лучше использовать константы с функциями, с которыми они идут вместе. Это применимо при работе с несколькими модулями, которые определяют одну и ту же константу, потому что некоторые из них могут быть устаревшими, и лучше всего синхронизировать функции и константы. При работе с ctypes (вызов функций напрямую) я должен был определить константу (из MSDN ) или вообще не использовать константу. Это просто рекомендация, которую я использую, в 99,9% случаев она, вероятно, не имеет значения (функционально).
 – 
CristiFati
20 Ноя 2017 в 02:54
3
Первое, что нужно сделать, - это запретить этой глупой функции «отключенных команд» что-либо делать. Если вы так сильно заботитесь о своем файле glob.glob, вам определенно не нужно os.scandir командовать вами.
 – 
ShadowRanger
29 Ноя 2017 в 21:29
3
Эта вторая часть моего комментария (подстановка без подстановочных знаков на самом деле не выполняет итерацию папки и никогда не повторяет) означает, что это совершенно эффективное решение проблемы (медленнее, чем прямой вызов os.path.isdir или os.path.lexist, поскольку это набор вызовов функций уровня Python и строковых операций, прежде чем он решит, что эффективный путь жизнеспособен, но без дополнительных системных вызовов или операций ввода-вывода, которые на порядки медленнее).
 – 
ShadowRanger
29 Ноя 2017 в 21:38

Это самый простой способ проверить, существует ли файл. Просто потому что файл существовал, когда вы установили флажок, не гарантирует , что он будет там, когда вам нужно будет его открыть.

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")
153
MrWonderful 14 Янв 2018 в 07:07
17
Пока вы намереваетесь получить доступ к файлу, состояние гонки действительно существует , независимо от того, как построена ваша программа. Ваша программа не может гарантировать, что другой процесс на компьютере не изменил файл. Это то, что Эрик Липперт называет экзогенным исключением.. Вы не можете избежать этого, предварительно проверив наличие файла.
 – 
Isaac Supeene
23 Ноя 2014 в 21:37
Лучшая практика - сделать окно (файловой) операции как можно меньшим с последующей надлежащей обработкой исключений.
 – 
un33k
28 Июл 2018 в 05:52

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
143
Cody Piersall 4 Дек 2017 в 17:45

Предпочитайте заявление о попытке. Это считается лучшим стилем и позволяет избежать условий гонки.

Не верьте мне на слово. Эта теория имеет множество подтверждений. Вот парочка:

124
Honest Abe 28 Апр 2014 в 05:01
3
Пожалуйста, добавьте лучшие источники в поддержку вашего утверждения.
 – 
BlueTrin
10 Сен 2015 в 12:09
11
Указанная ссылка «Избегание условий гонки» (поддержка разработчиков Apple) не поддерживает ваш ответ. Это касается только использования временных файлов, содержащих конфиденциальную информацию, в плохо спроектированных операционных системах, которые не помещают временные файлы / каталоги в изолированную программную среду с ограниченными разрешениями. В любом случае использование try...except не помогает решить эту проблему.
 – 
jstine
28 Сен 2015 в 18:38
Проблема с этим методом заключается в том, что если у вас есть важный фрагмент кода, зависящий от файла, который не существует, включение его в предложение except: приведет к тому, что исключение, возникающее в этой части вашего кода, вызовет сбивающее с толку сообщение (вторая ошибка возникла при обработке первой.)
 – 
Camion
24 Май 2019 в 13:43

Как проверить, существует ли файл, с помощью Python без использования оператора try?

Теперь, доступный начиная с 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 не совсем верно, потому что каталоги не являются файлами (кроме unix-смысла, что все является файлом).

>>> 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 вы просто пытаетесь прочитать ваш файл, ожидая, что он там есть, а если нет, вы перехватываете исключение и выполняете любое резервное поведение, которое имеет смысл.

Если вы хотите проверить, существует ли файл, прежде чем пытаться его прочитать, и вы, возможно, удаляете его, а затем используете несколько потоков или процессов, или другая программа знает об этом файле и может его удалить - вы рискуете состояние гонки , если вы проверяете, что оно существует, потому что вы затем участвуете в гонке , чтобы открыть его до того, как его состояние (его существование) изменится.

Условия гонки очень трудно отлаживать, потому что есть очень маленькое окно, в котором они могут привести к сбою вашей программы.

Но если это ваша мотивация, вы можете получить значение оператора try с помощью диспетчера контекста suppress.

Избежание условий гонки без оператора try: 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()
... 
>>> 

Для более ранних версий Pythons вы могли использовать собственный 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() могут быть истинными для одного и того же пути.

Но если вы изучите источник этой функции, вы Увидим, что он действительно использует оператор 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

Все, что он делает, это использует заданный путь, чтобы увидеть, может ли он получить статистику по нему, перехватывает OSError и затем проверяет, является ли это файлом, если он не вызывает исключение.

Если вы собираетесь что-то сделать с файлом, я бы посоветовал напрямую попробовать это с помощью try, за исключением того, чтобы избежать состояния гонки:

try:
    with open(path) as f:
        f.read()
except OSError:
    pass

os.access

Для Unix и Windows доступен os.access, но для использования вы должны передавать флаги, и он не делает различий между файлами и каталогами. Это больше используется для проверки, имеет ли реальный вызывающий пользователь доступ в среде с повышенными привилегиями:

import os
os.access(path, os.F_OK)

Он также страдает теми же проблемами состояния гонки, что и isfile. Из документов:

Примечание. Используя access (), чтобы проверить, авторизован ли пользователь, например, открытие файла до того, как это сделать, с помощью 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!) Проходить без уведомления, что является хорошим способом скрыть ошибки.

Похоже, это побуждает пользователей применять неэффективные методы.

118
Aaron Hall 25 Фев 2018 в 23:45
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.

86
atlas 16 Май 2017 в 19:36
9
Это неверный ответ. os.path.exists возвращает истину для вещей, которые не являются файлами, например каталогов. Это дает ложные срабатывания. См. Другие ответы, рекомендующие os.path.isfile.
 – 
Chris Johnson
1 Авг 2015 в 16:56

Проверка файлов и папок с помощью os.path.isfile(), os.path.isdir() и os.path.exists()

Предполагая, что «путь» является допустимым путем, в этой таблице показано, что возвращает каждая функция для файлов и папок:

enter image description here

Вы также можете проверить, является ли файл определенным типом файла, используя 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
81
Tom Fuller 8 Окт 2016 в 15:43

В 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():
    ...
71
Peter Mortensen 27 Май 2017 в 04:00
3
Могу я спросить: в чем преимущество использования модуля pathlib вместо модуля os в python3 для этой проверки?
 – 
Joko
25 Фев 2016 в 11:55
3
pathlib - это ООП-решение Python для путей. Вы можете сделать с ним гораздо больше. Если вам просто нужно проверить наличие, преимущество не так велико.
 – 
KaiBuxe
25 Фев 2016 в 13:44

Не похоже, что есть значимая функциональная разница между try / except и 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'

Другое дело, если вам нужна блокировка файлов.

65
chad 25 Авг 2015 в 06:12
3
Это неверный ответ. os.path.exists возвращает истину для вещей, которые не являются файлами, например каталогов. Это дает ложные срабатывания. См. Другие ответы, рекомендующие os.path.isfile.
 – 
Chris Johnson
1 Авг 2015 в 16:54
6
В вашем третьем примере я создаю ссылку с именем filepath с правильным временем, а BAM вы перезаписываете целевой файл. Вы должны сделать open(filepath, 'wx') в блоке try...except, чтобы избежать проблемы.
 – 
spectras
24 Авг 2015 в 17:05
1
Во втором примере, по крайней мере, в Windows, вы получите OSError, если filepath + '.old' уже существует: "В Windows, если dst уже существует, OSError будет вызвана, даже если это файл; может не иметь возможности реализовать атомарное переименование, когда dst называет существующий файл ".
 – 
Tom Myddeltyn
24 Май 2016 в 17:14
@TomMyddeltyn: Начиная с Python 3.3, os.replace переносимо выполняет тихую замену целевого файла (это идентично поведению os.rename в Linux) (ошибка возникает только в том случае, если конечное имя существует и является каталогом). Итак, вы застряли на 2.x, но у пользователей Py3 уже несколько лет есть хороший вариант.
 – 
ShadowRanger
29 Ноя 2017 в 21:14
В примере rename: это все равно нужно делать с try / except. os.rename (или os.replace в современном Python) является атомарным; установка проверки и переименования приводит к ненужной гонке и дополнительным системным вызовам. Просто сделай try: os.replace(filepath, filepath + '.old') except OSError: pass
 – 
ShadowRanger
29 Ноя 2017 в 21:17

Вы можете попробовать это (безопаснее):

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] Нет такого файла или каталога: 'any.txt')

Затем, в зависимости от результата, ваша программа может просто продолжать работать оттуда или вы можете закодировать, чтобы остановить ее, если хотите.

58
Peter Mortensen 27 Май 2017 в 03:43
18
Исходный вопрос был задан для решения, которое не использует try
 – 
rrs
23 Апр 2014 в 17:10
5
Этот ответ упускает из виду суть ОП. Проверка наличия файла - это не то же самое, что проверка возможности его открытия. Бывают случаи, когда файл действительно существует, но по разным причинам вы не можете его открыть.
 – 
Chris Johnson
17 Фев 2016 в 21:52

Хотя я всегда рекомендую использовать операторы try и except, вот несколько возможностей для вас (я лично предпочитаю использовать os.access):

  1. Попробуйте открыть файл:

    Открытие файла всегда проверяет его существование. Вы можете сделать функцию так:

    def File_Existence(filepath):
        f = open(filepath)
        return True
    

    Если значение равно False, выполнение будет остановлено с необработанной ошибкой IOError. или OSError в более поздних версиях Python. Чтобы поймать исключение, вы должны использовать предложение try except. Конечно вы всегда можете используйте оператор try except` вроде этого (спасибо hsandt за то, что заставил задуматься):

    def File_Existence(filepath):
        try:
            f = open(filepath)
        except IOError, OSError: # Note OSError is for later versions of Python
            return False
    
        return True
    
  2. Используйте 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
    
  3. Используйте 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), чтобы вы могли, надеюсь, определить свою проблему. Я надеюсь, что это помогает! :)

50
Peter Mortensen 27 Май 2017 в 03:52

Дата: 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']}
50
Azat Ibrakov 23 Дек 2018 в 13:46

Дополнительно os.access():

if os.access("myfile", os.R_OK):
    with open("myfile") as fp:
        return fp.read()

Будучи R_OK, W_OK и X_OK флагами для проверки разрешений (doc).

35
armatita 4 Май 2016 в 18:24

Если вы уже импортировали NumPy для других целей, тогда нет необходимости импортировать другие библиотеки, такие как pathlib, os, paths и т. Д.

import numpy as np
np.DataSource().exists("path/to/your/file")

Это вернет истину или ложь в зависимости от его существования.

18
JayRizzo 1 Сен 2018 в 04:00

Вы можете написать предложение Брайана без 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
17
Peter Mortensen 27 Май 2017 в 03:48

Я являюсь автором пакета, который существует уже около 10 лет, и в нем есть функция, которая напрямую решает этот вопрос. Обычно, если вы работаете в системе, отличной от Windows, она использует Popen для доступа к find. Однако, если вы работаете в Windows, он реплицирует find с помощью эффективного обходчика файловой системы.

Сам код не использует блок try ... кроме определения операционной системы и, таким образом, направляет вас к "Unix" -стилю find или ручному построению 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/898ec/898ec8c8e8c8e8c8e8c8e8e8e8d08e8e8e8e8b8e6 /pox/shutils.py#L190

16
Peter Mortensen 27 Май 2017 в 03:59

Убедитесь, что файл или каталог существует

Вы можете воспользоваться этими тремя способами:

Примечание 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+, устанавливается с помощью pip для Python 2)

from pathlib import Path
Path(filename).exists()
16
Ali Hallaji 4 Мар 2018 в 09:24

Добавление еще одного небольшого изменения, которое не совсем отражено в других ответах.

Это будет обрабатывать случай, когда 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):
15
Marcel Wilson 7 Апр 2017 в 19:10
3
if (x) return true; else return false; на самом деле просто return x. Ваши последние четыре строки могут стать return os.path.isfile(file_path). Пока мы занимаемся этим, всю функцию можно упростить как return file_path and os.path.isfile(file_path).
 – 
Shahbaz
5 Янв 2017 в 01:50
Вы должны быть осторожны с return x в случае if (x). Python будет считать пустую строку False, и в этом случае мы вернем пустую строку вместо bool. Цель этой функции - всегда возвращать bool.
 – 
Marcel Wilson
5 Янв 2017 в 20:08
1
Правда. Однако в этом случае x равно os.path.isfile(..), так что это уже bool.
 – 
Shahbaz
5 Янв 2017 в 20:10
os.path.isfile(None) вызывает исключение, поэтому я добавил проверку if. Я, вероятно, мог бы просто обернуть это в try / except, но я чувствовал, что так это более явно.
 – 
Marcel Wilson
5 Янв 2017 в 20:13
3
return file_path and os.path.isfile(file_path)
 – 
Peter Wood
6 Апр 2017 в 13:35

Вот однострочная команда Python для среды командной строки Linux. Я нахожу это ОЧЕНЬ УДОБНЫМ, так как я не такой уж горячий парень с Bash.

python -c "import os.path; print os.path.isfile('/path_to/file.xxx')"

Надеюсь, это поможет.

14
Love and peace - Joe Codeswell 29 Авг 2015 в 19:15
6
Однострочная проверка в bash: [ -f "${file}" ] && echo "file found" || echo "file not found" (то же самое, что и if [ ... ]; then ...; else ...; fi).
 – 
flotzilla
1 Окт 2015 в 10:48

Вы можете использовать библиотеку "OS" Python:

>>> import os
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.txt") 
True
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.tx")
False
11
Peter Mortensen 27 Май 2017 в 03:49
5
Это неверный ответ. os.path.exists возвращает истину для вещей, которые не являются файлами, например каталогов. Это дает ложные срабатывания. См. Другие ответы, рекомендующие os.path.isfile.
 – 
Chris Johnson
1 Авг 2015 в 16:55
Функция Johnson, os.path.exists () проверяет, существует ли путь в системе. ПУТЬ может быть КАТАЛОГОМ или ФАЙЛОМ. Он будет работать нормально в обоих случаях. Пожалуйста, попробуйте какой-нибудь пример
 – 
Pradip Das
2 Авг 2015 в 17:51
Итак, этот ответ работает. Большой. Iff - это не путь к файлу. Это то, о чем был вопрос? Нет.
 – 
Debosmit Ray
15 Апр 2016 в 02:33
Это зависит. Если цель определения существования «файла» состоит в том, чтобы выяснить, существует ли уже путь (и, следовательно, не является путем, где новые данные могут быть сохранены без удаления другой информации), то exists в порядке. Если цель состоит в том, чтобы определить, безопасно ли открывать предположительно существующий файл, то критика оправдана и существует недостаточно точно. К сожалению, OP не указывает, какая цель является желаемой (и, вероятно, больше этого не будет).
 – 
starturtle
5 Сен 2017 в 14:24

Как проверить, существует ли файл, без использования оператора try?

В 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 ( просто совет ).

11
Peter Mortensen 27 Май 2017 в 03:57
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)
9
bubble 9 Окт 2015 в 00:22
Да, isReadableFile(path,fileName) вернет True, если файл доступен и доступен для чтения процессу \ программе \ потоку
 – 
Khaled.K
9 Авг 2015 в 10:46

Если причина, по которой вы проверяете, заключается в том, чтобы вы могли сделать что-то вроде 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
5096
Georgy 13 Май 2019 в 13:40
39
Что касается первого замечания (используйте "попробуйте", если проверьте перед открытием), к сожалению, это не сработает, если вы хотите открыть для добавления, будучи уверенным, что он существует раньше, поскольку режим 'a' будет создан, если не существует.
 – 
makapuf
20 Июн 2018 в 10:58
6
Обратите внимание, что FileNotFoundError был введен в Python 3. Если вам также необходимо поддерживать Python 2.7, а также Python 3, вы можете вместо этого использовать IOError (который является подклассом FileNotFoundError) stackoverflow.com/a/21368457/1960959
 – 
scottclowe
29 Мар 2019 в 16:44
6
Вы можете открыть его для «обновления» (open('file', 'r+')), а потом искать до конца.
 – 
kyrill
30 Апр 2019 в 20:45
Open-and-seek-to-end - это не то же самое, что open-for-append (по крайней мере, в системах posix). «режим добавления» всегда будет правильно записывать в конец файла, даже если другие вещи изменяют файл между моментом его открытия и моментом записи. Открытие для записи / обновления и поиск до конца рискуют повредить данные файла, если несколько вещей попытаются записать в один и тот же файл одновременно. К сожалению, я считаю, что единственный безопасный для условий гонки способ открыть для добавления и убедиться, что файл существует первым, - это использовать вместо этого подпрограммы нижнего уровня os.open () (O_APPEND без O_CREAT).
 – 
Foogod
19 Фев 2020 в 20:31
Хорошая точка зрения. Хотя, если несколько «вещей» попытаются записать в один и тот же файл одновременно без какой-либо синхронизации, возможно, он все равно будет поврежден. А если вы все же используете синхронизацию, вам не нужно беспокоиться о состоянии гонки.
 – 
kyrill
19 Фев 2020 в 23:44

У вас есть функция os.path.exists :

import os.path
os.path.exists(file_path)

Это возвращает True как для файлов, так и для каталогов, но вместо этого вы можете использовать

os.path.isfile(file_path)

Чтобы проверить, является ли это конкретным файлом. Он следует символическим ссылкам.

2087
Community 19 Окт 2018 в 11:58

В отличие от 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
953
Boris 3 Мар 2020 в 20:45
import os.path

if os.path.isfile(filepath):
616
Ankur Agarwal 21 Июн 2017 в 23:33

Если файл предназначен для открытия, вы можете использовать один из следующих способов:

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!')

ОБНОВЛЕНИЕ

Чтобы избежать путаницы и на основании полученных ответов, текущий ответ находит либо файл , либо каталог с заданным именем.

35
Tshilidzi Mudau 21 Фев 2020 в 16:28
9
Это неверный ответ. os.path.exists возвращает истину для вещей, которые не являются файлами, например каталогов. Это дает ложные срабатывания. См. Другие ответы, рекомендующие os.path.isfile.
 – 
Chris Johnson
1 Авг 2015 в 16:55
Также возникла проблема с ложным срабатыванием.
 – 
Zorglub29
20 Май 2018 в 00:33
docs.python.org/3/library/os. path.html # os.path.exists К приведенному выше утверждению от chris >> os.path.exists (path)> Вернуть True, если путь относится к существующему пути или открытому файлу дескриптор. Возвращает False для неработающих символических ссылок. На некоторых платформах эта функция может возвращать False, если не предоставлено разрешение на выполнение os.stat () для запрошенного файла, даже если путь физически существует. Изменено в версии 3.3: теперь путь может быть целым числом: True возвращается, если это дескриптор открытого файла, в противном случае - False. Изменено в версии 3.6: принимает объект, подобный пути.
 – 
JayRizzo
1 Сен 2018 в 02:24
if os.path.isfile(path_to_file):
    try: 
        open(path_to_file)
            pass
    except IOError as e:
        print "Unable to open file"

Создание исключений считается приемлемым и питоническим подходом для управления потоком в вашей программе. Рассмотрите возможность обработки отсутствующих файлов с помощью IOErrors. В этой ситуации будет вызвано исключение IOError, если файл существует, но у пользователя нет разрешений на чтение.

SRC: http://www.pfinn.net/python-check-if-file-exists. html

20
CONvid19 18 Июл 2015 в 20:41
3
OP спросил, как проверить, существует ли файл. Возможно, файл существует, но вы не сможете его открыть. Поэтому использование открытия файла в качестве прокси для проверки того, существует ли файл, неверно: будет иметь ложноотрицательные результаты.
 – 
Chris Johnson
17 Фев 2016 в 21:58