[Python] Как проверить, существует ли файл?


Answers

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

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

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

Question

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




I'm the author of a package that's been around for about 10 years, and it has a function that addresses this question directly. Basically, if you are on a non-Windows system, it uses Popen to access find . However, if you are on Windows, it replicates find with an efficient filesystem walker.

The code itself does not use a try block… except in determining the operating system and thus steering you to the "Unix"-style find or the hand-buillt find . Timing tests showed that the try was faster in determining the OS, so I did use one there (but nowhere else).

>>> import pox
>>> pox.find('*python*', type='file', root=pox.homedir(), recurse=False)
['/Users/mmckerns/.python']

And the doc…

>>> 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']

>>>

The implementation, if you care to look, is here: https://github.com/uqfoundation/pox/blob/89f90fb308f285ca7a62eabe2c38acb87e89dad9/pox/shutils.py#L190




2017/12/22 :

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

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

Заявление о проблемах :

  1. Проверить файл (возможно: также папка («специальный» файл)?) Существование
  2. Не используйте блоки try / except / else / finally

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

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

    1.1. [Python]: pathlib.Path. is_file ()

    • Это лучший способ (и больше python ic) для обработки путей, но
    • Под капотом он делает то же самое ( pathlib.py , line ~ # 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]: с менеджерами контекста Statement . Или:

    • Создай:

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


    Но они кажутся обертками поверх try/except/else/finally блоков, как [Python]: оператор with утверждает:

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

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


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

  4. [Python]: os. доступ ( путь, режим, *, 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, не используйте его, если вы не знаете, что делаете:

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

    ( Win specific): Поскольку msvcr * ( vcruntime * ) экспортирует семейство функций [MSDN]: _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", 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"/tmp1", os.F_OK)
    -1
    

    Примечания :

    • Вместо этого путь hardcoding libc ( "/lib/x86_64-linux-gnu/libc.so.6" ), который может (и, скорее всего, будет) изменяться в разных системах, None (или пустая строка) может быть передан в конструктор CDLL ( ctypes.CDLL(None).access(b"/tmp", os.F_OK) ). Согласно [человеку]: DLOPEN (3) :

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

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

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

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

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

    • Выиграть :

      (py35x64_test) e:\Work\Dev\\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\\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 ( 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 , потому что они могут помешать вам выполнить ряд неприятных проблем. Контр-пример, о котором я могу думать, - это производительность: такие блоки являются дорогостоящими, поэтому старайтесь не размещать их в коде, который должен запускаться сотнями тысяч раз в секунду (но поскольку (в большинстве случаев) он включает в себя доступ к диску, это не так).

Заключительное примечание (и) :

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



import os
path = /path/to/dir

root,dirs,files = os.walk(path).next()
if myfile in files:
   print "yes it exists"

This is helpful when checking for several files. Or you want to do a set intersection/ subtraction with an existing list.




You can use the "OS" library of Python:

>>> import os
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.txt") 
True
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.tx")
False



import os.path

if os.path.isfile(filepath):



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

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

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




import os
os.path.exists(path) # returns whether the path (dir or file) exists or not
os.path.isfile(path) # returns whether the file exists or not



if os.path.isfile(path_to_file):
    try: 
        open(path_to_file)
            pass
    except IOError as e:
        print "Unable to open file"

Raising exceptions is considered to be an acceptable, and Pythonic, approach for flow control in your program. Consider handling missing files with IOErrors. In this situation, an IOError exception will be raised if the file exists but the user does not have read permissions.

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




Additionally, os.access() :

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

Being R_OK , W_OK , and X_OK the flags to test for permissions ( doc ).




Here's a 1 line Python command for the Linux command line environment. I find this VERY HANDY since I'm not such a hot Bash guy.

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

I hope this is helpful.




If the file is for opening you could use one of the following techniques:

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



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 упрощает навигацию и выполнение стандартных действий с вашей операционной системой.

Для справки также см. share

Если вам нужны операции высокого уровня, используйте shutil .




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

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




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 есть много классных вещей: удобное globbing, проверка владельца файла, упрощение соединения и т. Д. Это стоит проверить. Если вы используете более старый 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



Links