Перевірте, чи є шлях дійсним у Python, не створюючи файл у цілі шляху


98

У мене є шлях (включаючи каталог та ім’я файлу).
Мені потрібно перевірити, чи ім'я файлу є дійсним, наприклад, якщо файлова система дозволить мені створити файл з таким ім'ям.
Ім'я файлу містить кілька символів Unicode .

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

Я дуже не хочу нічого уникати, якщо мені не доведеться.

Я б опублікував деякі приклади символів, з якими маю справу, але, очевидно, вони автоматично видаляються системою обміну стеків. У будь-якому випадку, я хочу зберегти стандартні сутності Unicode, як ö, і уникати лише тих речей, які недійсні в імені файлу.


Ось улов. У цілі шляху вже може бути (а може і не бути) файл. Мені потрібно зберегти цей файл, якщо він існує, і не створювати файл, якщо він не існує.

В основному я хочу перевірити, чи міг би я писати в шлях, не відкриваючи фактично шлях для запису (і автоматичне створення файлів / клонування файлів, що зазвичай тягне за собою).

Як такий:

try:
    open(filename, 'w')
except OSError:
    # handle error here

звідси

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

Я знаю, що можу:

if not os.access(filePath, os.W_OK):
    try:
        open(filePath, 'w').close()
        os.unlink(filePath)
    except OSError:
        # handle error here

Але це створить файл у filePath, який мені тоді доведеться os.unlink.

Врешті-решт, здається, що потрібно витратити 6 або 7 рядків, щоб виконати щось, що повинно бути настільки ж простим os.isvalidpath(filePath)чи подібним.


Окрім того, мені це потрібно для роботи на (принаймні) Windows та MacOS, тому я хотів би уникати речей, що стосуються певної платформи.

``


Якщо ви хочете перевірити, що шлях існує, і ви можете написати на нього, просто створіть і видаліть якийсь інший файл. Дайте йому унікальне ім’я (або настільки унікальне, наскільки ви можете), щоб уникнути проблем із кількома користувачами / багатьма потоками. В іншому випадку ви дивитесь на перевірку дозволів, які потраплять вас прямо в конкретну ОС.
Тоні Гопкінсон,

3
@Tony Hopkinson - В основному я хочу перевірити, чи не міг би я писати на шлях, фактично нічого не написавши .
Фальшиве ім’я

Якщо у вас немає нічого для запису у файл, то чому ви повинні знати, чи можете це зробити?
Карл Кнехтель

@Karl Knechtel - Якщо я напишу йому, і там уже є файл, це пошкодить наявний файл.
Фальшиве ім’я

2
@FakeName - Тут у вас завжди буде тонкий стан перегонів. Між тим, як перевірити, що файл не існує, але його можна було створити, а потім створити файл, його може створити якийсь інший процес, і ви все одно зробите файл. Звичайно, це залежить від вашого використання, є це реалістичною проблемою чи ні ...
похмуро 02.03.12

Відповіді:


155

tl; д-р

Викличте is_path_exists_or_creatable()функцію, визначену нижче.

Строго Python 3. Ось так ми і рухаємося.

Казка про два запитання

Питання "Як перевірити правильність імені шляху та, для дійсних імен шляхів, існування чи запис до цих шляхів?" це явно два окремі питання. Обидва вони цікаві, і жоден з них не отримав справді задовільної відповіді тут ... або, ну, де-небудь, що я міг зрозуміти.

Віккі «s відповідь , ймовірно , рубає ближче, але має чудові недоліки:

  • Без потреби відкривати ( ... а потім не вдається надійно закрити ) дескриптори файлів.
  • Зайве написання ( ... а потім неможливість надійного закриття чи видалення ) 0-байтових файлів.
  • Ігнорування помилок, специфічних для ОС, розмежування неігноруваних невірних імен шляхів та проблем файлової системи. Не дивно, що це критично важливо для Windows. ( Див. Нижче. )
  • Ігнорування умов перегонів, що виникають внаслідок зовнішніх процесів одночасно (пере) переміщення батьківських каталогів імені шляху, що перевіряється. ( Див. Нижче. )
  • Ігноруючи час очікування підключення, що виникає внаслідок цього імені шляху, яке знаходиться у застарілих, повільних або тимчасово недоступних файлових системах. Це може піддати публічні служби потенційним атакам DoS- Driven. ( Див. Нижче. )

Ми все це виправимо.

Запитання № 0: Що таке термін дії імені шляху?

Перш ніж кидати наші тендітні м’ясні костюми в болі, пронизані пітоном, ми, мабуть, повинні визначити, що ми маємо на увазі під „валідністю імені шляху”. Що саме визначає дійсність?

Під "дійсністю імені шляху" ми маємо на увазі синтаксичну правильність імені шляху щодо кореневої файлової системи поточної системи, незалежно від того, чи існує цей шлях або батьківські каталоги фізично. Ім'я шляху є синтаксично правильним за цим визначенням, якщо воно відповідає всім синтаксичним вимогам кореневої файлової системи.

Під "кореневою файловою системою" ми маємо на увазі:

  • У системах, сумісних з POSIX, файлова система підключена до кореневого каталогу ( /).
  • У Windows, файлова система, змонтована на %HOMEDRIVE%, буква диска з суфіксом двокрапки, що містить поточну інсталяцію Windows (як правило, але не обов’язково C:).

Значення "синтаксичної правильності", у свою чергу, залежить від типу кореневої файлової системи. Для ext4(і більшості, але не для всіх POSIX-сумісних) файлових систем ім’я шляху є синтаксично правильним тоді і лише тоді, коли це ім’я шляху:

  • Не містить нульових байтів (тобто \x00в Python). Це важка вимога для всіх файлових систем, сумісних з POSIX.
  • Не містить компонентів шляху довжиною більше 255 байт (наприклад, 'a'*256у Python). Компонент шляху є самим довгим підрядком імені шляху , що не містить /символ (наприклад, bergtatt, ind, i, і fjeldkamreneв дорожньому імені /bergtatt/ind/i/fjeldkamrene).

Синтаксична правильність. Коренева файлова система. Це воно.

Питання №1: Як тепер ми зробимо дійсність імені шляху?

Перевірка імен шляхів у Python напрочуд не інтуїтивна. Я тут твердо згоден з Fake Name : офіційний os.pathпакет повинен надати нестандартне рішення для цього. З невідомих (і, мабуть, незрозумілих) причин, це не так. На щастя, розгортання власного спеціального рішення - це не те, що викручувати кишечник ...

Добре, насправді так. Волохата; це неприємно; ймовірно, він бурчить, коли бурчить і хихикає, коли світиться. Але що ти будеш робити? Нутін.

Незабаром ми спустимося в радіоактивну прірву низькорівневого коду. Але спочатку поговоримо про магазин високого рівня. Стандарт os.stat()і os.lstat()функції викликають такі винятки, коли передаються недійсні імена шляхів:

  • Для імен шляхів, що проживають у неіснуючих каталогах, екземпляри FileNotFoundError.
  • Для імен шляхів, що знаходяться в існуючих каталогах:
    • В ОС Windows екземпляри WindowsError, winerrorатрибутом яких є 123(тобто ERROR_INVALID_NAME).
    • У всіх інших ОС:
    • Для імен шляхів, що містять нульові байти (тобто, '\x00'), екземпляри TypeError.
    • Для імен шляхів, що містять компоненти шляху, довші за 255 байт, екземплярами атрибута OSErrorяких errcodeє:
      • Під SunOS і * BSD сімейство операційних систем, errno.ERANGE. (Це, схоже, помилка на рівні ОС, інакше називана "вибірковим тлумаченням" стандарту POSIX.)
      • При всіх інших операційних систем, errno.ENAMETOOLONG.

Що найважливіше, це означає, що перевіряються лише назви шляхів, що знаходяться в існуючих каталогах. Функції os.stat()and os.lstat()викликають загальні FileNotFoundErrorвинятки, коли передаються імена шляхів, що перебувають у неіснуючих каталогах, незалежно від того, чи є ці імена недійсними чи ні. Існування каталогу має перевагу над недійсністю імені шляху.

Чи означає це, що імена шляхів, що перебувають у неіснуючих каталогах, не перевіряються? Так - якщо ми не змінимо ці імена шляхів для розміщення в існуючих каталогах. Однак це навіть безпечно? Чи не повинно зміна імені шляху заважати нам перевіряти оригінальну назву шляху?

Щоб відповісти на це запитання, згадайте згори, що синтаксично правильні імена шляхів у ext4файловій системі не містять компонентів шляху (A), що містять нульові байти або (B) довжиною понад 255 байт. Отже, ext4ім'я шляху є дійсним тоді і тільки тоді, коли всі компоненти шляху в цьому імені шляху є дійсними. Це стосується більшості реальних файлових систем, що представляють інтерес.

Чи насправді нам допомагає це педантичне розуміння? Так. Це зводить більшу проблему перевірки повного імені шляху одним махом до меншого завдання перевірки лише всіх компонентів шляху в цьому імені шляху. Будь-яке довільне ім'я шляху можна перевірити (незалежно від того, чи воно знаходиться в існуючому каталозі чи ні) крос-платформенним способом, дотримуючись наступного алгоритму:

  1. Розділіть це ім’я шляху на компоненти шляху (наприклад, ім’я шляху /troldskog/faren/vildу список ['', 'troldskog', 'faren', 'vild']).
  2. Для кожного такого компонента:
    1. Приєднайте ім'я шляху до каталогу, який гарантовано існує з цим компонентом, до нового тимчасового імені шляху (наприклад, /troldskog).
    2. Передайте цю назву шляху до os.stat()або os.lstat(). Якщо це ім'я шляху і, отже, цей компонент є недійсним, цей виклик гарантовано викликає виняток, який виявляє тип недійсності, а не загальний FileNotFoundErrorвиняток. Чому? Оскільки це ім’я шляху знаходиться в існуючому каталозі. (Циркулярна логіка є круговою.)

Чи гарантовано існує каталог? Так, але, як правило, лише один: найвищий каталог кореневої файлової системи (як визначено вище).

Передавання імен шляхів, що знаходяться в будь-якому іншому каталозі (і, отже, не гарантується його існування), os.stat()або os.lstat()запрошує умови перегонів, навіть якщо цей каталог раніше перевірявся на існування. Чому? Оскільки зовнішні процеси не можуть запобігти одночасному видаленню цього каталогу після того, як було проведено тестування, але до того, як це ім’я шляху буде передано os.stat()або os.lstat(). Розв’яжіть собак душевного божевілля!

Існує також істотна побічна вигода від вищезазначеного підходу: безпека. (Не що приємно?) В зокрема:

Фронтальні програми, що перевіряють довільні назви шляхів із ненадійних джерел, просто передаючи такі доріжки os.stat()або os.lstat()сприйнятливі до атак відмови в обслуговуванні (DoS) та інших махінацій. Зловмисні користувачі можуть намагатися неодноразово перевіряти імена шляхів, що перебувають у файлових системах, які, як відомо, застарілі або іншим чином повільні (наприклад, спільні ресурси NFS Samba); у такому випадку сліпе введення вхідних імен може призвести або до збою з часом очікування з’єднання, або споживання більше часу та ресурсів, ніж ваша слабка здатність протистояти безробіттю.

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

Втратили? Чудово. Давайте почнемо. (Припускається Python 3. Див. "Що таке тендітна надія на 300, leycec ?")

import errno, os

# Sadly, Python fails to provide the following magic number for us.
ERROR_INVALID_NAME = 123
'''
Windows-specific error code indicating an invalid pathname.

See Also
----------
https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
    Official listing of all such codes.
'''

def is_pathname_valid(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname for the current OS;
    `False` otherwise.
    '''
    # If this pathname is either not a string or is but is empty, this pathname
    # is invalid.
    try:
        if not isinstance(pathname, str) or not pathname:
            return False

        # Strip this pathname's Windows-specific drive specifier (e.g., `C:\`)
        # if any. Since Windows prohibits path components from containing `:`
        # characters, failing to strip this `:`-suffixed prefix would
        # erroneously invalidate all valid absolute Windows pathnames.
        _, pathname = os.path.splitdrive(pathname)

        # Directory guaranteed to exist. If the current OS is Windows, this is
        # the drive to which Windows was installed (e.g., the "%HOMEDRIVE%"
        # environment variable); else, the typical root directory.
        root_dirname = os.environ.get('HOMEDRIVE', 'C:') \
            if sys.platform == 'win32' else os.path.sep
        assert os.path.isdir(root_dirname)   # ...Murphy and her ironclad Law

        # Append a path separator to this directory if needed.
        root_dirname = root_dirname.rstrip(os.path.sep) + os.path.sep

        # Test whether each path component split from this pathname is valid or
        # not, ignoring non-existent and non-readable path components.
        for pathname_part in pathname.split(os.path.sep):
            try:
                os.lstat(root_dirname + pathname_part)
            # If an OS-specific exception is raised, its error code
            # indicates whether this pathname is valid or not. Unless this
            # is the case, this exception implies an ignorable kernel or
            # filesystem complaint (e.g., path not found or inaccessible).
            #
            # Only the following exceptions indicate invalid pathnames:
            #
            # * Instances of the Windows-specific "WindowsError" class
            #   defining the "winerror" attribute whose value is
            #   "ERROR_INVALID_NAME". Under Windows, "winerror" is more
            #   fine-grained and hence useful than the generic "errno"
            #   attribute. When a too-long pathname is passed, for example,
            #   "errno" is "ENOENT" (i.e., no such file or directory) rather
            #   than "ENAMETOOLONG" (i.e., file name too long).
            # * Instances of the cross-platform "OSError" class defining the
            #   generic "errno" attribute whose value is either:
            #   * Under most POSIX-compatible OSes, "ENAMETOOLONG".
            #   * Under some edge-case OSes (e.g., SunOS, *BSD), "ERANGE".
            except OSError as exc:
                if hasattr(exc, 'winerror'):
                    if exc.winerror == ERROR_INVALID_NAME:
                        return False
                elif exc.errno in {errno.ENAMETOOLONG, errno.ERANGE}:
                    return False
    # If a "TypeError" exception was raised, it almost certainly has the
    # error message "embedded NUL character" indicating an invalid pathname.
    except TypeError as exc:
        return False
    # If no exception was raised, all path components and hence this
    # pathname itself are valid. (Praise be to the curmudgeonly python.)
    else:
        return True
    # If any other exception was raised, this is an unrelated fatal issue
    # (e.g., a bug). Permit this exception to unwind the call stack.
    #
    # Did we mention this should be shipped with Python already?

Готово. Не коситись на цей код. ( Кусає. )

Запитання №2: Можливо, недійсне існування або можливість створення імені шляху, так?

Тестування існування чи можливості створення недійсних імен шляхів, з огляду на вищевказане рішення, здебільшого тривіальне. Маленький ключ тут - викликати раніше визначену функцію перед тестуванням пройденого шляху:

def is_path_creatable(pathname: str) -> bool:
    '''
    `True` if the current user has sufficient permissions to create the passed
    pathname; `False` otherwise.
    '''
    # Parent directory of the passed path. If empty, we substitute the current
    # working directory (CWD) instead.
    dirname = os.path.dirname(pathname) or os.getcwd()
    return os.access(dirname, os.W_OK)

def is_path_exists_or_creatable(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname for the current OS _and_
    either currently exists or is hypothetically creatable; `False` otherwise.

    This function is guaranteed to _never_ raise exceptions.
    '''
    try:
        # To prevent "os" module calls from raising undesirable exceptions on
        # invalid pathnames, is_pathname_valid() is explicitly called first.
        return is_pathname_valid(pathname) and (
            os.path.exists(pathname) or is_path_creatable(pathname))
    # Report failure on non-fatal filesystem complaints (e.g., connection
    # timeouts, permissions issues) implying this path to be inaccessible. All
    # other exceptions are unrelated fatal issues and should not be caught here.
    except OSError:
        return False

Готово і зроблено. Хіба що не зовсім.

Запитання №3: Можливо, недійсне існування або запис до імені шляху у Windows

Існує застереження. Звичайно, є.

Як визнає офіційна os.access()документація :

Примітка: Операції вводу-виводу можуть провалитися навіть тоді, коли це os.access()вказує на їх успіх, особливо для операцій над мережевими файловими системами, які можуть мати семантику дозволів, а не звичайну бітову модель дозволу POSIX.

Нікого не здивуй, тут звичайним підозрюваним є Windows. Завдяки широкому використанню списків контролю доступу (ACL) у файлових системах NTFS, спрощена модель бітового дозволу POSIX погано відповідає базовій реальності Windows. Хоча це (можливо) не винна Python, проте це може викликати занепокоєння для сумісних з Windows додатків.

Якщо це ви, потрібна більш надійна альтернатива. Якщо переданий шлях не існує, ми замість цього намагаємось створити тимчасовий файл, який гарантовано буде негайно видалений у батьківському каталозі цього шляху - більш портативний (якщо дорогий) тест на створення:

import os, tempfile

def is_path_sibling_creatable(pathname: str) -> bool:
    '''
    `True` if the current user has sufficient permissions to create **siblings**
    (i.e., arbitrary files in the parent directory) of the passed pathname;
    `False` otherwise.
    '''
    # Parent directory of the passed path. If empty, we substitute the current
    # working directory (CWD) instead.
    dirname = os.path.dirname(pathname) or os.getcwd()

    try:
        # For safety, explicitly close and hence delete this temporary file
        # immediately after creating it in the passed path's parent directory.
        with tempfile.TemporaryFile(dir=dirname): pass
        return True
    # While the exact type of exception raised by the above function depends on
    # the current version of the Python interpreter, all such types subclass the
    # following exception superclass.
    except EnvironmentError:
        return False

def is_path_exists_or_creatable_portable(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname on the current OS _and_
    either currently exists or is hypothetically creatable in a cross-platform
    manner optimized for POSIX-unfriendly filesystems; `False` otherwise.

    This function is guaranteed to _never_ raise exceptions.
    '''
    try:
        # To prevent "os" module calls from raising undesirable exceptions on
        # invalid pathnames, is_pathname_valid() is explicitly called first.
        return is_pathname_valid(pathname) and (
            os.path.exists(pathname) or is_path_sibling_creatable(pathname))
    # Report failure on non-fatal filesystem complaints (e.g., connection
    # timeouts, permissions issues) implying this path to be inaccessible. All
    # other exceptions are unrelated fatal issues and should not be caught here.
    except OSError:
        return False

Однак зауважте, що навіть цього може бути недостатньо.

Завдяки Контролю доступу користувачів (UAC), постійно неповторна Windows Vista та всі подальші її ітерації відверто брешуть про дозволи, що належать до системних каталогів. Коли користувачі, які не є адміністраторами, намагаються створити файли як у канонічному, так C:\Windowsі в C:\Windows\system32каталогах, UAC поверхнево дозволяє користувачеві робити це, фактично ізолюючи всі створені файли у "Віртуальному магазині" у профілі цього користувача. (Хто міг уявити, що обман користувачів матиме шкідливі довгострокові наслідки?)

Це божевілля. Це Windows.

Докажи це

Сміємо? Настав час перевірити вищезазначені тести.

Оскільки NULL є єдиним символом, забороненим у назвах шляхів у файлових системах, орієнтованих на UNIX, давайте використаємо це, щоб продемонструвати холодну, тверду істину - ігноруючи неігноровані хитрощі Windows, які, відверто кажучи, набридають і гнівають мене однаковою мірою:

>>> print('"foo.bar" valid? ' + str(is_pathname_valid('foo.bar')))
"foo.bar" valid? True
>>> print('Null byte valid? ' + str(is_pathname_valid('\x00')))
Null byte valid? False
>>> print('Long path valid? ' + str(is_pathname_valid('a' * 256)))
Long path valid? False
>>> print('"/dev" exists or creatable? ' + str(is_path_exists_or_creatable('/dev')))
"/dev" exists or creatable? True
>>> print('"/dev/foo.bar" exists or creatable? ' + str(is_path_exists_or_creatable('/dev/foo.bar')))
"/dev/foo.bar" exists or creatable? False
>>> print('Null byte exists or creatable? ' + str(is_path_exists_or_creatable('\x00')))
Null byte exists or creatable? False

Поза розумом. Поза болем. Ви знайдете проблеми з портативністю Python.


3
Так, це був я! Спроба об’єднати між собою переносний регулярний вираз, що перевіряє ім’я шляху, є вправною справою і гарантовано невдалою в загальних випадках. Розглянемо довжину імені шляху в Windows, наприклад: "Максимальний шлях у 32 767 символів є приблизним, оскільки префікс '\\? \' Може бути розширений системою до більшого рядка під час виконання, і це розширення стосується загальної довжини . " Враховуючи це, насправді технічно неможливо побудувати регулярний вираз, що відповідає лише дійсним іменам шляхів. Набагато розумніше просто перейти до Python.
Сесіл Каррі

2
Ага. Я (неохоче) бачу. Ви робите щось дивніше, ніж злом регулярного виразу. Так, що гарантовано не в змозі навіть важче. Це також повністю не дозволяє вирішити питання, про яке йдеться, а не "Як видалити недійсні підряди з базового імені Windows?" (... який, за власним упущенням, вам не вдається вирішити - знову ж таки через крайові випадки), але "Як перехресно перевірити правильність імені шляху та, для дійсних імен шляхів, існування чи запис цих шляхів?"
Сесіл Каррі

1
Обмеження, що стосуються файлової системи, безумовно, є вагомою проблемою, але це обмежує обидва шляхи. Для фронтальних додатків, які використовують довільні імена шляхів з ненадійних джерел, сліпе виконання читання - це найкраща пропозиція; у цьому випадку примусове використання кореневої файлової системи є не лише розумним, але й розумним. Однак для інших програм база даних може бути досить надійною, щоб надати доступ до нестримної файлової системи. Це досить залежне від контексту, я б сказав. Дякую за те, що ви це помітно зауважили, Ніхто ! Я додам застереження вище.
Сесіл Каррі

2
Що стосується номенклатури, я педантичний шанувальник префіксів імен тестерів is_. Це моя вада в характері. Тим не менше, належним чином зазначено: ти не можеш подобатися всім, а іноді і нікому. ;)
Сесіл Каррі

1
У Fedora 24, python 3.5.3, ім'я шляху із вбудованими нульовими символами викидає: ValueError: вбудований нульовий байт ... потрібно додати: `` за винятком ValueError as exc: return False '' до або після захоплення TypeError.
mMerlin

47
if os.path.exists(filePath):
    #the file is there
elif os.access(os.path.dirname(filePath), os.W_OK):
    #the file does not exists but write privileges are given
else:
    #can not write there

Зверніть увагу, що це path.existsможе призвести до збою з більшої кількості причин, ніж просто the file is not thereтому, можливо, вам доведеться проводити більш точні тести, такі як тестування, чи існує каталог, що містить тощо.


Після мого обговорення з OP виявилося, що головна проблема полягає в тому, що ім'я файлу може містити символи, заборонені файловою системою. Звичайно, їх потрібно видалити, але OP хоче зберегти стільки людського читання, скільки дозволяє файлова система.

На жаль, я не знаю жодного хорошого рішення для цього. Однак відповідь Сесіл Каррі пильніше розглядає виявлення проблеми.


Ні. Мені потрібно повернути true, якщо файл на шляху існує або його можна створити . Мені потрібно повернути false, якщо шлях недійсний (через те, що на вікнах містяться недійсні символи).
Фальшиве ім'я

or can be createdну я не читав цього з вашого запитання. Зчитування дозволів певною мірою буде залежати від платформи.
Ніхто не відходить від SE

1
@Fake Name: Так, це призведе до видалення деяких залежностей від платформи, але все-таки деякі платформи пропонують речі, яких інші не роблять, і немає простого способу обернути це для всіх них. Я оновив свою відповідь, подивіться там.
Ніхто не від'їжджає від SE

1
Я поняття не маю, чому цю відповідь підтримали. Він не супроводжується віддаленим вирішенням основного питання - що, лаконічно, є: "Перевірити імена шляхів, будь ласка?" Перевірка дозволів на шлях тут є допоміжним (і в основному ігнорується) питанням. Незважаючи на те, що виклик os.path.exists(filePath)технічно викликає винятки щодо недійсних імен шляхів, ці винятки потрібно було б чітко вловити та диференціювати від інших не пов’язаних винятків. Більше того, той самий виклик повертається Falseна існуючі шляхи, на які поточний користувач не має дозволів на читання. Словом, погано.
Сесіл Каррі

1
@CecilCurry: Щоб відповісти на ваші запитання: Погляньте на історію редагування запитання. Як і у більшості питань, спочатку це було не так чітко, і навіть зараз формулювання заголовка може бути зрозуміле інакше, ніж ви сказали.
Ніхто не від'їжджає від SE

9

Як щодо Python 3, як щодо:

try:
    with open(filename, 'x') as tempfile: # OSError if file exists or is invalid
        pass
except OSError:
    # handle error here

З опцією "х" нам також не доведеться турбуватися про умови перегонів. Дивіться документацію тут .

Тепер це ВИБУДЕ створити тимчасовий файл, який ще не існує, якщо він ще не існує - якщо тільки ім’я недійсне. Якщо ви можете жити з цим, це значно спрощує ситуацію.


2
На даний момент проект, який потребував цього, вийшов настільки далеко за межі, коли відповідь є навіть актуальною, що я не можу прийняти відповідь.
Фальшиве ім'я

Як не дивно, практична відповідь недостатньо хороша. Незалежно від того, я думаю, ви могли побачити, чи існує файл. Якщо так, спробуйте скопіювати файл в іншому місці, а потім спробуйте перезаписати.
The Matt

5
open(filename,'r')   #2nd argument is r and not w

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

try:
    open(filename,'r')
    return True
except IOError:
    try:
        open(filename, 'w')
        return True
    except IOError:
        return False

Також подивіться тут про дозволи на Windows


1
Щоб уникнути необхідності явно від'єднати () тестовий файл, ви можете використовувати, tempfile.TemporaryFile()який автоматично знищить тимчасовий файл, коли він виходить за межі області дії.
D_Bye 02.03.12

@FakeName Код інший, я міг би використати os.access у другій частині, але якби ви перейшли за посиланням, яке я дав, ви б переконалися, що це не дуже гарна ідея, це залишає вам можливість спробувати насправді відкрити шлях для письма.
vikki

Я будую свої шляхи os.path.join, тому у мене не виникає `` проблем, що уникають. Крім того, у мене насправді не виникає проблем з дозволом на каталог . У мене каталог (і ім'я файлу) ім'я проблема.
Фальшиве ім’я

@FakeName у цьому випадку вам потрібно лише спробувати відкрити його (писати не потрібно), python видає помилку, якщо filenameмістить недійсні символи. Я відредагував відповідь
vikki

1
@HelgaIliashenko Відкриття для запису перезапише існуючий файл (зробить його порожнім), навіть якщо ви негайно закриєте його, не записавши на нього. Ось чому я спочатку відкрив для читання, тому що таким чином, якщо ви не отримаєте помилку, ви знаєте, що існує існуючий файл.
vikki

-7

спробуйте os.path.existsце перевірить шлях і повернеться, Trueякщо існує, а Falseякщо ні.


1
Ні. Мені потрібно повернути true, якщо файл на шляху існує або його можна створити . Мені потрібно повернути false, якщо шлях недійсний (через те, що на вікнах містяться недійсні символи).
Фальшиве ім'я

який тип недійсного символу?
Нілеш,

Не знаю - це специфічна платформа.
Фальшиве ім'я

2
Насправді, специфічна для файлової системи.
Piotr Kalinowski
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.