Как проверить, существует ли файл без исключений? - PullRequest
5031 голосов
/ 17 сентября 2008

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

Ответы [ 38 ]

4608 голосов
/ 17 сентября 2008

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

Если вы не планируете открывать файл немедленно, вы можете использовать os.path.isfile

Возвращает True, если путь является существующим обычным файлом. Это следует за символическими ссылками, поэтому оба значения islink () и isfile () могут иметь значение true для одного и того же пути.

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
1926 голосов
/ 17 сентября 2008

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

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

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

os.path.isfile(file_path)

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

892 голосов
/ 17 сентября 2008

В отличие от isfile(), exists() вернет True для каталогов.
Поэтому в зависимости от того, хотите ли вы только простые файлы или каталоги, вы будете использовать isfile() или exists(). Вот простой вывод REPL.

>>> print os.path.isfile("/etc/password.txt")
True
>>> print os.path.isfile("/etc")
False
>>> print os.path.isfile("/does/not/exist")
False
>>> print os.path.exists("/etc/password.txt")
True
>>> print os.path.exists("/etc")
True
>>> print os.path.exists("/does/not/exist")
False
550 голосов
/ 17 сентября 2008
import os.path

if os.path.isfile(filepath):
270 голосов
/ 16 января 2012

Использование os.path.isfile() с os.access():

import os
import os.path

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"
252 голосов
/ 17 сентября 2008
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
213 голосов
/ 20 июня 2017

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

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

Постановка задачи :

  1. Проверить файл ( спорный : также папка ("специальный" файл)?) Существование
  2. Не использовать Попробуйте / , за исключением / еще / наконец блоков

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

  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 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 ) . Итак, ваш код попробуйте / за исключением бесплатно, но ниже в стековом кадре есть (по крайней мере) один такой блок. Это также относится к другим функциям (, включая os.path.isfile).

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

    • Это более изящный (и более python ic) способ обработки путей, но
    • Под капотом он делает точно то же самое ( 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
      
  2. [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 (обратите внимание, что это только для демонстрационных целей, не пытайтесь написать такой код для production ):

        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. подавлять (* исключения ) - который был специально , предназначенный для выборочного подавление исключений


    Но, похоже, они являются обертками над try / за исключением / else / наконец блоков, как [Python 3]: оператор с сообщает:

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

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


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

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

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

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

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

    Поскольку я также работаю в C , я также использую этот метод, потому что под капотом он вызывает native 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 )
    • Я использую _waccess , чтобы тот же код работал на Python3 и Python2 (несмотря на Unicode связанные различия между их)
    • Хотя это относится к очень специфической области, это не было упомянуто ни в одном из предыдущих ответов


    Аналог 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]: ДЛОПЕН (3) :

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

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

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

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

  6. Другой (отсталый) обходной путь ( gainarie ) - это (как я это называю) подход sysadmin : используйте Python в качестве оболочка для выполнения команд оболочки

    • Win

      (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
      

Итог :

  • До использовать попробовать / за исключением / еще / наконец блоков, потому что они могут предотвратить возникновение ряда неприятных проблем. Контр-пример, о котором я могу подумать, - это производительность: такие блоки являются дорогостоящими, поэтому постарайтесь не помещать их в код, который предполагается запускать сотни тысяч раз в секунду (но поскольку (в большинстве случаев) он предполагает доступ к диску, это не будет так).

Конечная (ые) заметка (и) :

  • Я постараюсь держать его в курсе, любые предложения приветствуются, я добавлю что-нибудь полезное, что придет в ответ
146 голосов
/ 27 июня 2013

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

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")
133 голосов
/ 08 февраля 2014

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
117 голосов
/ 04 ноября 2009

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

Не верь мне на слово. Есть много поддержки этой теории. Вот пара:

...