Проверьте, действителен ли путь в Python, не создавая файл в целевом пути

98

У меня есть путь (включая каталог и имя файла).
Мне нужно проверить, является ли имя файла допустимым, например, если файловая система позволяет мне создать файл с таким именем.
В имени файла есть символы Юникода .

Можно с уверенностью предположить, что сегмент каталога в пути действителен и доступен ( я пытался сделать вопрос более применимым, и, очевидно, я зашел слишком далеко ).

Я очень не хочу убегать от чего-либо, если мне не придется .

Я бы опубликовал некоторые из примеров символов, с которыми я имею дело, но, очевидно, они автоматически удаляются системой обмена стеками. В любом случае, я хочу сохранить стандартные объекты 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 Гопкинсон - В основном я хочу , чтобы проверить , если я мог бы написать на путь фактически не писать ничего .
Поддельное имя
Если вам нечего записывать в файл, тогда зачем вам знать, можете ли вы?
Карл Кнехтель
@Karl Knechtel - Если я напишу в него, а там уже есть файл, это повредит существующий файл.
Fake Name
2
@FakeName - у вас всегда будет тонкое состояние гонки. Между проверкой того, что файл не существует, но может быть создан, и последующим созданием файла, какой-то другой процесс может его создать, и вы все равно испортите файл. Конечно, реальная проблема зависит от вашего использования ...
detly

Ответы:

155

tl; dr

Вызовите is_path_exists_or_creatable()функцию, определенную ниже.

Строго Python 3. Вот так мы и катимся.

Повесть о двух вопросах

Вопрос: «Как мне проверить правильность имени пути и, для действительных имен, наличие или возможность записи этих путей?» это явно два отдельных вопроса. Оба они интересны, и ни один из них не получил действительно удовлетворительного ответа здесь ... или, ну, в любом месте , где я мог бы grep.

Викки «s ответ , вероятно , рубит ближе, но имеет замечательные недостатки:

  • Излишне открывать ( ... а затем не удается надежно закрыть ) дескрипторы файлов.
  • Излишняя запись ( ... а затем невозможность надежного закрытия или удаления ) 0-байтовых файлов.
  • Игнорирование ошибок, связанных с ОС, различие между неотвратимыми недопустимыми именами пути и игнорируемыми проблемами файловой системы. Неудивительно, что под Windows это критично. ( См. Ниже. )
  • Игнорирование условий гонки, возникающих из-за того, что внешние процессы одновременно (повторно) перемещают родительские каталоги проверяемого пути. ( См. Ниже. )
  • Игнорирование тайм-аутов соединения, возникающих из-за того, что этот путь находится в устаревших, медленных или иным образом временно недоступных файловых системах. Это может подвергнуть общедоступные сервисы потенциальным DoS- атакам. ( См. Ниже. )

Мы все это исправим.

Вопрос № 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пакет должен предоставлять готовое решение для этого. По неизвестным (и, вероятно, неопровержимым) причинам это не так. К счастью, разворачивая собственное одноранговой решение не что выворачивающий ...

Хорошо, это действительно так. Волосатый; это мерзко; он, вероятно, хихикает, бормоча, и хихикает, когда светится. Но что ты собираешься делать? Nuthin '.

Скоро мы спустимся в радиоактивную бездну низкоуровневого кода. Но сначала поговорим о магазине высокого уровня. Стандарт 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()и 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(). Развяжите псов головокружительного безумия!

У вышеупомянутого подхода также есть существенное побочное преимущество: безопасность. (Не что приятно?) В частности:

Внешние приложения, проверяющие произвольные имена путей из ненадежных источников, просто передавая такие имена пути к атакам типа «отказ в обслуживании» (DoS) и другим махинациям «черной шляпы» os.stat()или os.lstat()подвержены им. Злоумышленники могут неоднократно пытаться проверять имена путей в файловых системах, которые заведомо устарели или работают медленно (например, общие ресурсы 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 внешне позволяет пользователю сделать это в то время как на самом деле изолировать все созданные файлы в «виртуальный магазин» в профиле этого пользователя. (Кто бы мог подумать, что обман пользователей приведет к пагубным долгосрочным последствиям?)

Это безумие. Это винда.

Докажите это

Смеем ли мы? Пришло время протестировать вышеперечисленные тесты.

Поскольку 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_. Это недостаток моего характера. Тем не менее, как следует отметить: нельзя всем угодить, а иногда никому не угодишь. ;)
Cecil Curry
1
В Fedora 24, python 3.5.3 имя пути со встроенными нулевыми символами выдает: ValueError: встроенный нулевой байт ... необходимо добавить: ``, кроме ValueError как 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 хочет поддерживать столько читабельности, сколько позволяет файловая система.

К сожалению, я не знаю хорошего решения для этого. Однако в ответе Сесила Карри более подробно рассматривается обнаружение проблемы.

Никто не уходит от ЮВ
источник
Нет. Мне нужно вернуть истину, если файл по указанному пути существует или может быть создан . Мне нужно вернуть false, если путь недействителен (из-за того, что в окнах содержатся недопустимые символы).
Fake Name
or can be createdну, я не прочитал это из вашего вопроса. Чтение разрешений будет в некоторой степени зависеть от платформы.
Никто не уезжает из SE
1
@Fake Name: Да, это удалит некоторые зависимости от платформы, но все же некоторые платформы предлагают вещи, которых нет на других, и нет простого способа обернуть это для всех. Я обновил свой ответ, посмотрите там.
Никто не уезжает из SE
1
Понятия не имею, почему за этот ответ проголосовали. Она не приходит удаленно примыкающей к решению основного вопроса - который в сжатой форме, является: «Validate имен путей, пожалуйста» Проверка разрешений на путь - это дополнительный (и в значительной степени игнорируемый) вопрос. Хотя вызов to 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

С опцией «x» нам также не нужно беспокоиться об условиях гонки. Смотрите документацию здесь .

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

Стивен Миллер
источник
2
На данный момент проект, который нуждался в этом, зашел так далеко за пределы того момента, когда ответ даже актуален, что я не могу принять ответ.
Fake Name
Как ни странно, практического ответа недостаточно. В любом случае, я полагаю, вы могли видеть, существует ли файл. Если это так, попробуйте скопировать файл в другое место, а затем попробуйте перезаписать.
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

Также посмотрите здесь о разрешениях на окнах

Викки
источник
1
Чтобы избежать необходимости явно unlink () тестового файла, вы можете использовать, tempfile.TemporaryFile()который автоматически уничтожит временный файл, когда он выйдет за пределы области видимости.
D_Bye 02
@FakeName Код другой, я мог бы использовать os.access во второй части, но если бы вы перешли по ссылке, которую я дал, вы бы увидели, что это не очень хорошая идея, это оставляет вам возможность попробовать открыть путь для записи.
vikki 02
Я строю свои пути os.path.join, поэтому у меня нет проблем с побегом. Кроме того, у меня действительно нет проблем с правами доступа к каталогам . У меня проблемы с именем каталога (и имени файла) .
Fake Name
@FakeName в этом случае вам нужно только попробовать и открыть его (вам не нужно писать), python выдает ошибку, если он filenameсодержит недопустимые символы. Я отредактировал ответ
vikki 02
1
@HelgaIliashenko Открытие для записи перезапишет существующий файл (сделает его пустым), даже если вы сразу закроете его, не записывая в него. Вот почему я сначала открывал для чтения, потому что в этом случае, если вы не получаете сообщение об ошибке, вы знаете, что существует существующий файл.
vikki
-7

попробуйте, os.path.existsэто проверит путь и вернется, Trueесли он существует, а Falseесли нет.

Нилеш
источник
1
Нет. Мне нужно вернуть истину, если файл по указанному пути существует или может быть создан . Мне нужно вернуть false, если путь недействителен (из-за того, что в окнах содержатся недопустимые символы).
Поддельное имя
какой тип недопустимого символа?
Nilesh 02
Не знаю - это зависит от платформы.
Fake Name
2
Фактически, зависит от файловой системы.
Петр Калиновский