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

Ответы:

5156

Если причина, по которой вы проверяете, заключается в том, что вы можете сделать что-то подобное 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
rslite
источник
40
Что касается первого замечания (используйте «попробовать», если проверка перед открытием), к сожалению, это не будет работать, если вы хотите открыть для добавления, будучи уверенным, что он существует раньше, так как режим «а» будет создан, если не существует.
Макапуф
6
Обратите внимание, что это FileNotFoundErrorбыло введено в Python 3. Если вам также необходимо поддерживать Python 2.7, а также Python 3, вы можете использовать IOErrorвместо него (какие FileNotFoundErrorподклассы) stackoverflow.com/a/21368457/1960959
scottclowe
7
@makapuf Вы можете открыть его для «обновления» ( open('file', 'r+')) и затем искать до конца.
Kyrill
2111

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

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

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

os.path.isfile(file_path)

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

PierreBdR
источник
967

В отличие от 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
bortzmeyer
источник
320

Используйте 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")
Югаль Джиндл
источник
60
Наличие нескольких условий, некоторые из которых являются излишними, менее ясно и явно.
Вим
10
Это также избыточно. Если файл не существует, os.access()вернет false.
Маркиз Лорн
9
@EJP В Linux файлы могут существовать, но не доступны.
e-info128
8
Поскольку вы import os, вам не нужно import os.pathснова, так как он уже является частью os. Вам просто нужно импортировать, os.pathесли вы собираетесь использовать функции os.pathтолько из osсебя, а не из себя, чтобы импортировать меньшую вещь, но по мере использования os.accessи os.R_OK, второй импорт не нужен.
Шут
287
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
benefactual
источник
2
Как правило, не рекомендуется именовать переменные так же, как имена методов.
Гомункул Ретулли
245

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

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

Постановка проблемы :

  1. Проверить наличие файла ( спорный : также папка («специальный» файл)?)
  2. Не используйте блоки try / исключением / 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 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

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

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

    • Это любитель (и более питон 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поведение (обратите внимание, что это только для демонстрационных целей, не пытайтесь писать такой код для производства ):

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


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

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

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


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

  4. [Python 3]: ос. доступа ( путь, режим, *, dir_fd = None, effective_ids = False, 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 также возможен через [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 (несмотря на юникод связанные различия между ними)
    • Хотя это относится к очень конкретной области, она не упоминалась ни в одном из предыдущих ответов


    Lnx ( Ubtu (16 x 64) ) аналог , а также:

    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" ), который может (и, скорее всего, будет) различаться в разных системах, None (или пустая строка) можно передать конструктору CDLL ( ctypes.CDLL(None).access(b"/tmp", os.F_OK)). Согласно [man7]: DLOPEN (3) :

      Если имя файла 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) , которые являются оболочкой 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
    • Никс ( Lnx ( Убту )):

      [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

Итог :

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

Финальные заметки :

  • Я постараюсь держать это в курсе, любые предложения приветствуются, я включу что-нибудь полезное, что придет в ответ
CristiFati
источник
3
Можете ли вы уточнить это утверждение? «Хотя это не очень хорошая практика, я использую os.F_OK в вызове, но это только для ясности (его значение равно 0)»
sk8asd123
6
@ sk8asd123: В комментариях это сложно сделать: обычно лучше использовать константы с функциями, с которыми они вместе работают. Это применимо при работе с несколькими модулями, которые определяют одну и ту же константу, поскольку некоторые из них могут быть устаревшими, и лучше всего синхронизировать функции и константы. При работе с ctypes (непосредственный вызов функций) я должен был определить константу (из MSDN ) или вообще не использовать константу. Это просто руководство, которое я использую, в 99,9% это, вероятно, не имеет никакого значения (функционально).
CristiFati
3
@CristiFati: Начиная с 3.6, glob.iglobglob.globтакже) основаны наos.scandir , так что теперь лениво; чтобы получить первый удар в каталоге из 10M файлов, вы сканируете только до первого попадания. И даже до 3.6, если вы используете globметоды без каких-либо подстановочных знаков, функция умна: она знает, что вы можете сделать только один удар, поэтому она упрощает сглаживание до всего os.path.isdirилиos.path.lexists (в зависимости от того, заканчивается ли путь /).
ShadowRanger
3
Эта вторая часть моего комментария (без подстановочных символов глобализация на самом деле не выполняет итерацию папки и никогда не имеет) действительно означает, что это совершенно эффективное решение проблемы (медленнее, чем прямой вызов os.path.isdirили os.path.lexistпоскольку это набор вызовов функций уровня Python и строки операции, прежде чем он решит, что эффективный путь является жизнеспособным, но не требуется никаких дополнительных системных вызовов или операций ввода-вывода, что на несколько порядков медленнее).
ShadowRanger
154

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

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")
un33k
источник
17
Пока вы намереваетесь получить доступ к файлу, условие гонки существует , независимо от того, как построена ваша программа. Ваша программа не может гарантировать, что другой процесс на компьютере не изменил файл. Эрик Липперт называет это экзогенным исключением . Вы не можете избежать этого, предварительно проверив существование файла.
Исаак Супин
@IsaacSupeene Лучшая практика - сделать окно операции (файла) как можно
меньшим,
145

В 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
Коди Пирсолл
источник
124

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

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

pkoch
источник
3
Пожалуйста, добавьте лучшие источники в поддержку вашего заявления.
BlueTrin
11
Ссылка "Избегать условий гонки" (поддержка Apple Dev) не поддерживает ваш ответ. Это касается только использования временных файлов, которые содержат конфиденциальную информацию в плохо спроектированных операционных системах, которые неправильно ограничивают временные файлы / каталоги песочницей из-за ограниченных разрешений. Использование try...exceptне помогает решить эту проблему в любом случае.
2015 г.
Проблема этого метода заключается в том, что если у вас есть важный фрагмент кода, зависящий от несуществующего файла, то включение его в except:предложение приведет к тому, что исключение, возникающее в этой части вашего кода, вызовет сбивающее с толку сообщение (вторая ошибка возникает во время обработка первого.)
Camion
119

Как проверить, существует ли файл с использованием 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 менеджера контекста.

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

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

Это, кажется, поощряет пользователей принимать плохие методы.

Аарон Холл
источник
87
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.

атлас
источник
9
Этот ответ неверен. os.path.existsвозвращает true для вещей, которые не являются файлами, например, для каталогов. Это дает ложные срабатывания. Смотрите другие ответы, которые рекомендуют os.path.isfile.
Крис Джонсон
84

Тестирование файлов и папок с помощью 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
Том Фуллер
источник
72

В 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():
    ...
KaiBuxe
источник
3
Могу я спросить: в чем преимущество использования модуля 'pathlib' вместо модуля 'os' в python3 для этой проверки?
Джоко
3
pathlibявляется ООП-решением Python для путей. Вы можете сделать намного больше с этим. Если вам просто нужно проверить существование, преимущество не так велико.
KaiBuxe
65

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

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

Чад
источник
3
Этот ответ неверен. os.path.existsвозвращает true для вещей, которые не являются файлами, например, для каталогов. Это дает ложные срабатывания. Смотрите другие ответы, которые рекомендуют os.path.isfile.
Крис Джонсон
6
В третьем примере я создаю ссылку filepathс правильным временем, и BAM перезаписывает целевой файл. Вы должны сделать open(filepath, 'wx')в try...exceptблоке, чтобы избежать проблемы.
спектры
1
Во втором примере, по крайней мере, в Windows, вы получите, OSErrorесли filepath + '.old'уже существует: «В Windows, если dst уже существует, OSError будет вызываться, даже если это файл; может быть невозможно реализовать атомарное переименование, когда dst называет существующий файл. "
Том Мидделтын
@TomMyddeltyn: Начиная с Python 3.3,os.replace переносимо выполняет автоматическую замену файла назначения (он идентичен os.renameповедению Linux) (он только выдает ошибки, если имя назначения существует и является каталогом). Итак, вы застряли на 2.x, но у пользователей Py3 был хороший выбор уже несколько лет.
ShadowRanger
На renameпримере: это все еще должно быть сделано с try/ except. os.rename(или os.replaceна современном Python) является атомарным; проверка его, а затем переименование приводит к ненужной гонке и дополнительным системным вызовам. Просто сделайtry: os.replace(filepath, filepath + '.old') except OSError: pass
ShadowRanger
59

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

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

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

philberndt
источник
18
Оригинальный вопрос просил решение, которое не используетtry
rrs
5
Этот ответ не попадает в точку ОП. Проверка наличия файла - это не то же самое, что проверка возможности его открытия. В некоторых случаях файл существует, но по разным причинам его нельзя открыть.
Крис Джонсон
51

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

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

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

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

    Если это значение False, оно прекратит выполнение с неуправляемым IOError или OSError в более поздних версиях Python. Чтобы поймать исключение, вы должны использовать предложение try, кроме. Конечно, вы всегда можете использовать tryвыражение "исключение" вот так (спасибо 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его, он проверит наличие пути. Однако использование этого создаст дыру в безопасности, поскольку кто-то может атаковать ваш файл, используя время между проверкой прав доступа и открытием файла. Вместо этого вам следует перейти непосредственно к открытию файла вместо проверки его прав доступа. ( ЭСПЦ против 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)чтобы вы могли надеяться определить вашу проблему. Я надеюсь, что это помогает! :)

Zizouz212
источник
51

Дата: 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']}
Исчисление
источник
37

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

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

ОБНОВИТЬ

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

bergercookie
источник
9
Этот ответ неверен. os.path.existsвозвращает true для вещей, которые не являются файлами, например, для каталогов. Это дает ложные срабатывания. Смотрите другие ответы, которые рекомендуют os.path.isfile.
Крис Джонсон
получил ложную положительную проблему также.
Zorglub29
docs.python.org/3/library/os.path.html#os.path.exists К приведенному выше заявлению от chris >> os.path.exists (path)> верните True, если path ссылается на существующий путь или открытый дескриптор файла. Возвращает False для неработающих символических ссылок. На некоторых платформах эта функция может возвращать False, если не предоставлено разрешение на выполнение os.stat () для запрошенного файла, даже если путь физически существует. Изменено в версии 3.3: путь теперь может быть целым числом: True возвращается, если это дескриптор открытого файла, False в противном случае. Изменено в версии 3.6: Принимает объект, похожий на путь.
JayRizzo
36

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

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

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

Zgoda
источник
20
if os.path.isfile(path_to_file):
    try: 
        open(path_to_file)
            pass
    except IOError as e:
        print "Unable to open file"

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

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

CONvid19
источник
3
ОП спросил, как проверить, существует ли файл. Файл может существовать, но вы не можете его открыть. Поэтому использование открытия файла в качестве прокси-сервера для проверки, существует ли файл, является неправильным: будет иметь ложные отрицания.
Крис Джонсон
19

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

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

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

Durjoy
источник
18

Вы можете написать предложение Брайана без 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

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

Сам код не использует tryблок ... за исключением определения операционной системы и, следовательно, findперехода к стилю «Unix» или «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

Майк Маккернс
источник
17

Проверьте, существует ли файл или каталог

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

Примечание 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()
Али Халладжи
источник
16

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

Это будет обрабатывать случай 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):
Марсель Уилсон
источник
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).
Шахбаз
Вы должны быть осторожны return xв случае if (x). Python будет рассматривать пустую строку False, в этом случае мы будем возвращать пустую строку вместо bool. Цель этой функции - всегда возвращать bool.
Марсель Уилсон
1
Правда. В этом случае , однако, xэто os.path.isfile(..)так уже BOOL.
Шахбаз
os.path.isfile(None)вызывает исключение, поэтому я добавил проверку if. Я мог бы, вероятно, просто обернуть это в попытку / за исключением, но я чувствовал, что это было более явно таким образом.
Марсель Уилсон
3
return file_path and os.path.isfile(file_path)
Питер Вуд
15

Вот 1-строчная команда Python для среды командной строки Linux. Я нахожу это ОЧЕНЬ ХЕНДИ, так как я не такой горячий парень из Баш

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

Я надеюсь, что это полезно.

Любовь и мир - Джо Кодсвелл
источник
6
Однострочная проверка в bash: [ -f "${file}" ] && echo "file found" || echo "file not found"(что совпадает с if [ ... ]; then ...; else ...; fi).
Flotzilla
12

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

>>> import os
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.txt") 
True
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.tx")
False
Прадип Дас
источник
5
Этот ответ неверен. os.path.existsвозвращает true для вещей, которые не являются файлами, например, для каталогов. Это дает ложные срабатывания. Смотрите другие ответы, которые рекомендуют os.path.isfile.
Крис Джонсон
@Chris Johnson, функция os.path.exists () проверяет, существует ли путь в системе. ПУТЬ может быть КАТАЛОГОМ или ФАЙЛОМ. Это будет хорошо работать в обоих случаях. Пожалуйста, попробуйте какой-нибудь пример
Прадип Дас
Итак, этот ответ работает. Отлично. Если путь не путь к файлу. Это был вопрос? Нет.
Дебосмит Рэй
Это зависит. Если цель определения существования «файла» состоит в том, чтобы выяснить, существует ли уже путь (и, следовательно, не является ли он путем, в котором новые данные могут быть сохранены без удаления другой информации), то existsэто нормально. Если цель состоит в том, чтобы определить, безопасно ли открывать предположительно существующий файл, то критика оправдана и существует недостаточно точно. К сожалению, ОП не определяет, какая цель является желаемой (и, вероятно, больше не будет).
стартурт
12

Как проверить, существует ли файл, без использования оператора 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 ).

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

Inconnu
источник
9
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)
Khaled.K
источник
@ j6m8 да, isReadableFile(path,fileName)вернется, Trueесли файл доступен и читается процессом \ program \ thread
Khaled.K