Питання Як перевірити, чи існує файл?


Як дізнатися, чи існує файл, чи ні, не використовуючи try заява?


4361
2017-09-17 12:55


походження




Відповіді:


Якщо ви перевіряєте причину, ви можете зробити щось подібне 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

Щоб перевірити, чи є a Path об'єкт існує незалежно від того, чи це файл або каталог, використовувати exists():

if my_file.exists():
    # path exists

Ви також можете використовувати resolve() в try блок:

try:
    my_abs_path = my_file.resolve()
except FileNotFoundError:
    # doesn't exist
else:
    # exists

3962
2017-09-17 12:57



щодо першого зауваження (використовуйте "спробуйте", якщо перевірити перед відкриттям), на жаль, це не спрацює, якщо ви хочете відкрити для додавання, переконавшись, що він існує до того, як режим "a" створить, якщо він не існує. - makapuf
я отримав os.path.isfile не існує - JeromeJ


У вас є os.path.exists функція:

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

Це повертається True для файлів і каталогів, але замість цього ви можете використовувати

os.path.isfile(file_name)

щоб перевірити, чи це конкретно файл. Це випливає з символічних посилань.


1626
2017-09-17 12:57





На відміну від 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

837
2017-09-17 15:01





import os.path

if os.path.isfile(filepath):

468
2017-09-17 12:55





Використовуйте 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"

222
2018-01-16 05:57



маючи декілька умов, деякі з яких є зайвими, є менше чіткий і явний. - wim
Це також зайве. Якщо файл не існує, os.access() повернемо помилково. - user207421
@EJP У файлах linux можуть існувати, але не доступні. - e-info128


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

209
2017-09-17 12:56



Ця відповідь неправильна. os.path.exists Повертає правду для речей, які не є файлами, такими як каталоги. Це дає помилкові позитиви. Див. Інші відповідні рекомендації os.path.isfile. - Chris Johnson
Каталог - це тип файлу unix.stackexchange.com/questions/197439/... - James Roth


Це найпростіший спосіб перевірити наявність файлу. Просто оскільки Файл існував, коли ви перевірили, ні гарантія що він буде там, коли потрібно його відкрити.

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")

139
2018-06-27 13:38



Поки ви маєте намір отримати доступ до файлу, стану перегонів існує, незалежно від того, як будується ваша програма. Ваша програма не може гарантувати, що інший процес на комп'ютері не змінює файл. Це те, що Ерік Ліперт називає як екзогенний виняток. Ви не можете уникнути цього, перевіривши наявність файлу заздалегідь. - Isaac Supeene
@IsaacSupeene Найкраща практика полягає в тому, щоб зробити вікно операції (файл) якнайменше можливою, а потім виконати правильну обробку виключень - un33k


2017/12/22:

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

Примітка: кожен шматок Python Стандартний код бібліотеки, який я збираюся публікувати, належить до версії 3.5.3 (котирування документів є версією 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 блокувати навколо [Python]: os.Стат(path, *, dir_fd = Немає, follow_symlinks = True). Отже, ваш код є try/except безкоштовно, але внизу в рамці там (принаймні) один такий блок Це також стосується інших funcs (в тому числі  os.path.isfile)

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

    • Це шанувальник (і багато іншого pythonic) спосіб обробки шляхів, але
    • Під капотом це робить точно Те ж саме (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]: з твердженням контекстних менеджерів. Або:

    • Створити один:

      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]: The з заява стверджує:

    Це дозволяє загальним спробуй...окрім...нарешті схеми використання, які будуть інкапсульовані для зручного повторного використання.

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


    Оскільки ці файли повторюються над папками, (в більшості випадків) вони неефективні для нашої проблеми (є і винятки, наприклад, не підміни globbing - як зазначив @ShadowRanger), тому я не буду на них наполягати. Не кажучи вже про те, що в деяких випадках може знадобитися обробка файлу.

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

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

      ... перевірити, чи користувач, який викликає, має вказаний доступ до шлях. режим має бути F_OK перевірити існування шляху ...

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

    Оскільки я теж працюю С, Я також користуюся цим методом, тому що під капотом це викликає рідний APIс (знову ж таки, через "$ {PYTHON_SRC_DIR} / Modules / postixmodule.c"), але це також відкриває ворота для можливого помилки користувача, і це не так Pythonic як інші варіанти. Отже, як справедливо зазначив @AaronHall, не використовуйте його, якщо ви не знаєте, що ви робите:

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

    (Виграти специфічний): з msvcr *(vcruntime *) експорт a [MSDN]: _доступ, _доступ Сімейство функцій також приведемо приклад:

    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 пов'язані між собою відмінності)
    • Хоча це стосується дуже конкретної області, це не було згадано в жодному з попередніх відповідей


    The 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
    

    Примітки:

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

      Якщо ім'я файлу NULL, тоді повернута ручка для основного   програма Коли дано длсмим(), ця команда викликає пошук для a   символ у головній програмі, а потім всі об'єднані об'єкти, завантажені на   запуск програми, а потім всі загальні об'єкти, завантажені за допомогою dlopen() з   прапор RTLD_GLOBAL.

      • Основна (поточна) програма (python) пов'язана з libc, тому його символи (в тому числі access) буде завантажено
      • З цим слід поводитися обережно, оскільки функції, як main, Py_Main і (усі) інші доступні; називаючи їх може мати катастрофічні наслідки (за поточною програмою)
      • Це також не стосується Виграти (але це не така велика справа, оскільки msvcrt.dllзнаходиться в Росії "% SystemRoot% \ System32" який є в % PATH% за замовчуванням). Я хотів взяти щось далі і повторити цю поведінку Виграти (і подайте патч), але, як з'ясовується, [MSDN]: функція GetProcAddress тільки "бачить" експортується символи, тому, якщо хтось не оголошує функції головного виконуваного файлу як __declspec(dllexport) (чому на Землі регулярний людина зробить це?), основна програма є завантажуваною, але майже непридатною для використання
  5. Встановіть близько 3rd Партійний модуль з можливостями файлової системи

    Швидше за все, буде покладатися на один із перерахованих вище способів (можливо, з невеликими налаштуваннями).
    Одним із прикладів буде (знову ж таки Виграти специфічний) [GitHub]: розширення Python для Windows (pywin32), який є а Python Обгортання WINAPIс

    Але, оскільки це більше схоже на обхід, я зупиняюсь тут.

  6. Інший (незрозумілий) обхідний шлях (нагромаджувати) є (як мені подобається це називати) сисадмін підхід: використовувати 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 (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 блоки, тому що вони можуть завадити вам запустити серію неприємних проблем. Контр-приклад, який я можу уявити, - це продуктивність: такі блоки коштують дорого, тому не намагайтеся не розміщувати їх у коді, яким він повинен працювати сотні тисяч разів на секунду (так як (в більшості випадків) це передбачає доступ до диску, це не буде).

Остаточна примітка:

  • Я постараюся зберегти його в актуальному стані, будь ласка, будь ласка, будь-які пропозиції, я додам щось корисне, що піде на відповідь

137
2018-06-20 19:28



Чи можете ви розповісти про це твердження? "Хоча це не належна практика, я використовую os.F_OK в дзвінку, але це тільки для ясності (його значення - 0)" - sk8asd123
@ sk8asd123: Нам важко доручити це в коментарях: як правило, краще використовувати константи з функціями, з якими вони збираються разом. Це стосується роботи з декількома модулями, які визначають одну і ту ж константу, тому що деякі з них можуть не бути оновленими, і це найкраще для синхронізації функцій і констант. При роботі з ctypes (безпосередньо викликати функції), я повинен був визначити константу (від MSDN), або не використовуйте постійну взагалі. Це просто керівництво, яке я використовую, у 99,9%, вочевидь, це не має значення (функціонально). - CristiFati
@ CristiFati: станом на 3.6, glob.iglob (і glob.glob а також) базуються на os.scandir, тож ліниво зараз; щоб отримати перший удар у каталозі 10 М файлів, ви скануєте тільки, поки не досягнете першого удару. І навіть попередньо 3.6, якщо ви використовуєте glob методи без будь-яких підстановок, функція розумна: вона знає, що ви можете мати лише один удар, так що це спрощує шльопання просто os.path.isdir або os.path.lexists (залежно від того, чи закінчиться шлях /) - ShadowRanger
Ця друга частина мого коментаря (не підкреслена globbing насправді не повторювати папку, і ніколи не має) означає, що це ідеально ефективне рішення проблеми (повільніше, ніж прямо дзвінок os.path.isdir або os.path.lexist оскільки це купа викликів функцій рівня Python і рядових операцій, перш ніж він вирішить, що ефективний шлях є життєздатним, але додатковий системний виклик або введення / виведення не виконуються, що за замовчуванням повільніше). - ShadowRanger


Python 3.4+ має об'єктно-орієнтований модуль шляху: Патліб. Використовуючи цей новий модуль, ви можете перевірити, чи є файл таким:

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

Ви можете (і, як правило, слід) все ще використовувати a try/except блокувати при відкритті файлів:

try:
    with p.open() as f:
        # do awesome stuff
except OSError:
    print('Well darn.')

Модуль "Патліф" містить багато цікавих елементів: зручне кодування, перевірка власника файлу, легше входження до неї та ін. Варто перевірити. Якщо ви перебуваєте на старшому Python (версії 2.6 або пізнішої версії), ви все ще можете встановити шлях до піп:

# 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

121
2018-02-08 02:38