Vérifier si un chemin est valide en Python sans créer de fichier à la cible du chemin


98

J'ai un chemin (y compris le répertoire et le nom du fichier).
J'ai besoin de tester si le nom de fichier est valide, par exemple si le système de fichiers me permettra de créer un fichier avec un tel nom.
Le nom de fichier contient des caractères Unicode .

Il est prudent de supposer que le segment de répertoire du chemin est valide et accessible ( j'essayais de rendre la question plus applicable de manière générale, et apparemment, j'étais trop loin ).

Je ne veux vraiment pas avoir à échapper à quoi que ce soit à moins d'y être obligé .

Je publierais certains des exemples de caractères avec lesquels je suis en train de traiter, mais apparemment, ils sont automatiquement supprimés par le système d'échange de piles. Quoi qu'il en soit, je veux garder les entités Unicode standard comme ö, et n'échapper qu'aux choses qui ne sont pas valides dans un nom de fichier.


Voici le piège. Il se peut (ou non) déjà un fichier sur la cible du chemin. Je dois conserver ce fichier s'il existe et ne pas créer de fichier s'il n'existe pas.

Fondamentalement, je veux vérifier si je pourrais écrire sur un chemin sans ouvrir réellement le chemin pour l'écriture (et la création automatique de fichiers / le sabotage de fichiers que cela implique généralement).

En tant que tel:

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

d'ici

N'est pas acceptable, car cela écrasera le fichier existant, que je ne veux pas toucher (s'il y en a), ou créera ledit fichier si ce n'est pas le cas.

Je sais que je peux faire:

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

Mais cela créera le fichier à la filePath, ce que je devrais alors faire os.unlink.

En fin de compte, il semble que cela passe 6 ou 7 lignes pour faire quelque chose qui devrait être aussi simple os.isvalidpath(filePath)ou similaire.


En passant, j'ai besoin que cela fonctionne sur (au moins) Windows et MacOS, donc j'aimerais éviter les trucs spécifiques à la plate-forme.

''


Si vous souhaitez tester que le chemin existe et que vous pouvez y écrire, créez et supprimez simplement un autre fichier. Donnez-lui un nom unique (ou aussi unique que possible), pour éviter les problèmes multi-utilisateurs / multi-threads. Sinon, vous cherchez à vérifier les autorisations qui vous plongeront directement dans la confusion spécifique du système d'exploitation.
Tony Hopkinson

3
@Tony Hopkinson - Fondamentalement , je veux vérifier si je pouvais écrire sur un chemin sans écrire quoi que ce soit .
Fake Name

Si vous n'avez rien à écrire dans le fichier, pourquoi avez-vous besoin de savoir si vous en êtes capable?
Karl Knechtel

@Karl Knechtel - Si j'écris dessus, et qu'il y a déjà un fichier, cela endommagera le fichier existant.
Fake Name

2
@FakeName - Vous allez toujours avoir une condition de course subtile ici. Entre la vérification que le fichier n'existe pas mais pourrait être créé, puis la création du fichier, un autre processus pourrait le créer et vous réduirez le fichier de toute façon. Bien sûr, cela dépend de votre utilisation, qu'il s'agisse d'un problème réaliste ou non ...
detly

Réponses:


154

tl; dr

Appelez la is_path_exists_or_creatable()fonction définie ci-dessous.

Strictement Python 3. C'est comme ça que nous roulons.

Un conte de deux questions

La question "Comment tester la validité des chemins et, pour les chemins valides, l'existence ou l'écriture de ces chemins?" est clairement deux questions distinctes. Les deux sont intéressants, et ni l'un ni l'autre n'ont reçu de réponse vraiment satisfaisante ici ... ou, bien, partout où je pourrais grep.

Vikki de réponse HEWS probablement le plus proche, mais présente les inconvénients remarquables:

  • Ouverture inutile ( ... et échec de la fermeture fiable ) des descripteurs de fichiers.
  • Écriture inutile ( ... et échec de la fermeture ou de la suppression fiable ) de fichiers de 0 octet.
  • Ignorer les erreurs spécifiques au système d'exploitation faisant la distinction entre les chemins d'accès non valides non ignorables et les problèmes de système de fichiers ignorables Sans surprise, c'est essentiel sous Windows. ( Voir ci-dessous. )
  • Ignorer les conditions de concurrence résultant de processus externes (re) déplacer simultanément les répertoires parents du chemin à tester. ( Voir ci-dessous. )
  • Ignorer les délais de connexion résultant de ce chemin résidant sur des systèmes de fichiers obsolètes, lents ou temporairement inaccessibles. Cela pourrait exposer les services publics à des attaques potentielles liées au DoS . ( Voir ci-dessous. )

On va réparer tout ça.

Question n ° 0: Quelle est encore la validité du chemin d'accès?

Avant de lancer nos fragiles combinaisons de viande dans les moshpits de douleur criblés de python, nous devrions probablement définir ce que nous entendons par «validité de chemin». Qu'est-ce qui définit la validité, exactement?

Par «validité de chemin», nous entendons l' exactitude syntaxique d'un chemin par rapport au système de fichiers racine du système actuel - indépendamment du fait que ce chemin ou ses répertoires parents existent physiquement. Un chemin d'accès est syntaxiquement correct selon cette définition s'il est conforme à toutes les exigences syntaxiques du système de fichiers racine.

Par «système de fichiers racine», nous entendons:

  • Sur les systèmes compatibles POSIX, le système de fichiers est monté dans le répertoire racine ( /).
  • Sous Windows, le système de fichiers monté sur %HOMEDRIVE%, la lettre de lecteur avec le suffixe deux-points contenant l'installation actuelle de Windows (généralement mais pas nécessairement C:).

La signification de «correction syntaxique» dépend à son tour du type de système de fichiers racine. Pour ext4(et la plupart des systèmes de fichiers compatibles POSIX mais pas tous), un chemin d'accès est syntaxiquement correct si et seulement si ce chemin:

  • Ne contient aucun octet nul (c'est- \x00à- dire en Python). C'est une exigence absolue pour tous les systèmes de fichiers compatibles POSIX.
  • Ne contient aucun composant de chemin de plus de 255 octets (par exemple, 'a'*256en Python). Un composant de chemin est une plus longue sous - chaîne d'un chemin ne contenant pas de /caractère (par exemple bergtatt, ind, i, et fjeldkamrenedans le chemin d' accès /bergtatt/ind/i/fjeldkamrene).

Exactitude syntaxique. Système de fichiers racine. C'est ça.

Question n ° 1: Comment allons-nous maintenant faire la validité des chemins d'accès?

La validation des chemins d'accès en Python n'est étonnamment pas intuitive. Je suis totalement d'accord avec Fake Name ici: le os.pathpackage officiel devrait fournir une solution prête à l'emploi pour cela. Pour des raisons inconnues (et probablement non convaincantes), ce n'est pas le cas. Heureusement, le déroulement de votre propre solution ad hoc n'est pas si déchirant ...

OK, c'est en fait. C'est velu; c'est dégueulasse; il glousse probablement en ronflant et glousse quand il brille. Mais qu'est-ce que tu vas faire? Nuthin '.

Nous allons bientôt descendre dans l'abîme radioactif du code de bas niveau. Mais d'abord, parlons de boutique de haut niveau. La norme os.stat()et les os.lstat()fonctions lèvent les exceptions suivantes lors de la transmission de chemins d'accès non valides:

  • Pour les noms de chemin résidant dans des répertoires non existants, des instances de FileNotFoundError.
  • Pour les chemins résidant dans des répertoires existants:
    • Sous Windows, instances WindowsErrordont l' winerrorattribut est 123(c'est-à-dire ERROR_INVALID_NAME).
    • Sous tous les autres systèmes d'exploitation:
    • Pour les chemins contenant des octets nuls (c'est-à-dire '\x00'), des instances de TypeError.
    • Pour les chemins contenant des composants de chemin plus longs que 255 octets, les instances OSErrordont l' errcodeattribut est:
      • SunOS et la famille * BSD de systèmes d' exploitation, errno.ERANGE. (Cela semble être un bogue au niveau du système d'exploitation, autrement appelé "interprétation sélective" du standard POSIX.)
      • Dans tous les autres systèmes d' exploitation, errno.ENAMETOOLONG.

Fondamentalement, cela implique que seuls les chemins résidant dans les répertoires existants sont validables. Les fonctions os.stat()et os.lstat()lèvent des FileNotFoundErrorexceptions génériques lors de la transmission de noms de chemins résidant dans des répertoires non existants, que ces chemins soient invalides ou non. L'existence de l'annuaire a priorité sur l'invalidité du chemin.

Cela signifie-t-il que les noms de chemins résidant dans des répertoires non existants ne sont pas validables? Oui - sauf si nous modifions ces chemins pour qu'ils résident dans des répertoires existants. Mais est-ce même faisable en toute sécurité? La modification d'un chemin ne devrait-il pas nous empêcher de valider le chemin d'origine?

Pour répondre à cette question, rappelez ci-dessus que les noms de chemin syntaxiquement corrects sur le ext4système de fichiers ne contiennent aucun composant de chemin (A) contenant des octets nuls ou (B) de plus de 255 octets de longueur. Par conséquent, un ext4chemin est valide si et seulement si tous les composants de chemin dans ce chemin sont valides. Ceci est vrai pour la plupart des systèmes de fichiers d'intérêt réels .

Cette vision pédante nous aide-t-elle réellement? Oui. Cela réduit le plus gros problème de validation du chemin complet d'un seul coup au problème plus petit de valider uniquement tous les composants du chemin dans ce chemin. Tout chemin arbitraire peut être validé (indépendamment du fait que ce chemin réside ou non dans un répertoire existant) de manière multiplateforme en suivant l'algorithme suivant:

  1. Divisez ce chemin en composants de chemin (par exemple, le chemin /troldskog/faren/vilddans la liste ['', 'troldskog', 'faren', 'vild']).
  2. Pour chacun de ces composants:
    1. Joignez le chemin d'un répertoire garanti d'exister avec ce composant dans un nouveau chemin temporaire (par exemple, /troldskog).
    2. Transmettez ce chemin à os.stat()ou os.lstat(). Si ce chemin d'accès et donc ce composant n'est pas valide, cet appel est garanti pour déclencher une exception exposant le type d'invalidité plutôt qu'une FileNotFoundErrorexception générique . Pourquoi? Parce que ce chemin réside dans un répertoire existant. (La logique circulaire est circulaire.)

Existe-t-il un annuaire garanti? Oui, mais typiquement un seul: le répertoire le plus haut du système de fichiers racine (tel que défini ci-dessus).

Passer des noms de chemins résidant dans n'importe quel autre répertoire (et donc pas garanti d'exister) à os.stat()ou os.lstat()invite des conditions de concurrence, même si ce répertoire a été précédemment testé pour exister. Pourquoi? Parce que les processus externes ne peuvent pas être empêchés de supprimer simultanément ce répertoire après que ce test a été effectué mais avant que ce chemin ne soit passé à os.stat()ou os.lstat(). Libérez les chiens de la folie époustouflante!

L'approche ci-dessus présente également un avantage secondaire substantiel: la sécurité. (Est -ce pas ce bien?) Plus précisément:

Les applications frontales validant les noms de chemins arbitraires provenant de sources non fiables en transmettant simplement ces noms de chemins vers os.stat()ou os.lstat()sont susceptibles de subir des attaques par déni de service (DoS) et d'autres manigances au chapeau noir. Des utilisateurs malveillants peuvent tenter de valider à plusieurs reprises les noms de chemins résidant sur des systèmes de fichiers connus pour être obsolètes ou lents (par exemple, les partages NFS Samba); dans ce cas, la statistique aveugle des chemins d'accès entrants est susceptible d'échouer avec les délais de connexion ou de consommer plus de temps et de ressources que votre faible capacité à résister au chômage.

L'approche ci-dessus évite cela en validant uniquement les composants de chemin d'un chemin par rapport au répertoire racine du système de fichiers racine. (Même si cela est obsolète, lent ou inaccessible, vous avez des problèmes plus importants que la validation des chemins.)

Perdu? Génial. Commençons. (Python 3 supposé. Voir "Qu'est-ce que Fragile Hope pour 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?

Terminé. Ne plissez pas les yeux sur ce code. ( Ça mord. )

Question n ° 2: Peut-être une existence ou une créabilité de chemin d'accès invalide, hein?

Tester l'existence ou la créabilité de chemins d'accès éventuellement invalides est, étant donné la solution ci-dessus, la plupart du temps trivial. La petite clé ici est d'appeler la fonction précédemment définie avant de tester le chemin passé:

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

Fait et fait. Sauf pas tout à fait.

Question n ° 3: Peut-être une existence de nom de chemin ou une écriture non valide sous Windows

Il existe une mise en garde. Bien sûr que oui.

Comme l' admet la os.access()documentation officielle :

Remarque: les opérations d'E / S peuvent échouer même si cela os.access()indique qu'elles réussiraient, en particulier pour les opérations sur les systèmes de fichiers réseau qui peuvent avoir une sémantique d'autorisations au-delà du modèle de bits d'autorisation POSIX habituel.

Sans surprise, Windows est le suspect habituel ici. Grâce à l'utilisation extensive des listes de contrôle d'accès (ACL) sur les systèmes de fichiers NTFS, le modèle simpliste de bits d'autorisation POSIX correspond mal à la réalité Windows sous-jacente. Bien que ce ne soit (sans doute) pas la faute de Python, cela pourrait néanmoins être préoccupant pour les applications compatibles Windows.

Si c'est vous, une alternative plus robuste est souhaitée. Si le chemin passé n'existe pas , nous essayons à la place de créer un fichier temporaire garanti d'être immédiatement supprimé dans le répertoire parent de ce chemin - un test de créabilité plus portable (bien que coûteux):

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

Notez, cependant, que même cela peut ne pas suffire.

Grâce au contrôle d'accès utilisateur (UAC), le Windows Vista toujours inimitable et toutes les itérations ultérieures de celui-ci mentent de manière flagrante sur les autorisations relatives aux répertoires système. Lorsque des utilisateurs non-administrateurs tentent de créer des fichiers dans le répertoire canonique C:\Windowsou dans les C:\Windows\system32répertoires, l'UAC autorise superficiellement l'utilisateur à le faire tout en isolant en fait tous les fichiers créés dans un "magasin virtuel" dans le profil de cet utilisateur. (Qui aurait pu imaginer que tromper les utilisateurs aurait des conséquences néfastes à long terme?)

C'est fou. C'est Windows.

Prouve le

Osons-nous? Il est temps de tester les tests ci-dessus.

Étant donné que NULL est le seul caractère interdit dans les chemins d'accès sur les systèmes de fichiers orientés UNIX, exploitons-le pour démontrer la froide et dure vérité - en ignorant les manigances Windows non ignorables, qui m'ennuient et me mettent en colère dans une égale mesure:

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

Au-delà de la raison. Au-delà de la douleur. Vous trouverez des problèmes de portabilité Python.


3
Ouais, c'était moi! Tenter de regrouper une regex de validation de chemin d'accès cross-portable est un exercice futile et échouera garanti pour les cas extrêmes courants. Considérez la longueur du chemin d'accès sous Windows, par exemple: "Le chemin maximum de 32 767 caractères est approximatif, car le préfixe '\\? \' Peut être étendu à une chaîne plus longue par le système au moment de l'exécution, et cette extension s'applique à la longueur totale . " Compte tenu de cela, il est techniquement impossible de construire une expression régulière correspondant uniquement à des chemins valides. Il est beaucoup plus raisonnable de s'en remettre à Python à la place.
Cecil Curry

2
Ah. Je vois (à contrecœur). Vous faites quelque chose d'encore plus étrange que de pirater une regex. Ouais, c'est garanti d'échouer encore plus dur. Cela échoue également complètement à répondre à la question en question, qui n'est pas "Comment supprimer des sous-chaînes non valides d'un nom de base spécifique à Windows?" (... que, par votre propre omission, vous ne parvenez pas à résoudre - encore une fois à cause de cas extrêmes) mais "Comment tester de manière croisée la validité des chemins et, pour les chemins valides, l'existence ou l'écriture de ces chemins?"
Cecil Curry

1
Les contraintes spécifiques au système de fichiers sont certainement une préoccupation valable - mais elles vont dans les deux sens. Pour les applications frontales consommant des chemins arbitraires provenant de sources non fiables, effectuer des lectures à l'aveugle est au mieux une proposition risquée; dans ce cas, forcer l'utilisation du système de fichiers racine est non seulement judicieux mais prudent. Pour d'autres applications, cependant, la base d'utilisateurs peut être suffisamment fiable pour accorder un accès non interdit au système de fichiers. Cela dépend assez du contexte, je dirais. Merci d'avoir noté cela astucieusement, Personne ! J'ajouterai une mise en garde ci-dessus.
Cecil Curry

2
En ce qui concerne la nomenclature, je suis un fan pédant de préfixer les noms de testeurs par is_. C'est mon défaut de caractère. Néanmoins, dûment noté: vous ne pouvez pas plaire à tout le monde, et parfois vous ne pouvez plaire à personne. ;)
Cecil Curry

1
Sur Fedora 24, python 3.5.3, un nom de chemin avec un caractère nul incorporé jette: ValueError: octet nul incorporé ... il faut ajouter: `` `` sauf ValueError as exc: return False '' `` avant ou après le trap 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

Notez que cela path.existspeut échouer pour plus de raisons que simplement the file is not therepour que vous deviez faire des tests plus fins comme tester si le répertoire contenant existe, etc.


Après ma discussion avec l'OP, il s'est avéré que le problème principal semble être que le nom du fichier peut contenir des caractères qui ne sont pas autorisés par le système de fichiers. Bien sûr, ils doivent être supprimés mais l'OP souhaite conserver autant de lisibilité humaine que le système de fichiers le permet.

Malheureusement, je ne connais aucune bonne solution pour cela. Cependant, la réponse de Cecil Curry examine de plus près la détection du problème.


Non. Je dois retourner true si le fichier sur le chemin existe ou peut être créé . Je dois retourner false si le chemin est invalide (en raison de la présence de caractères invalides sur Windows).
Fake Name

or can be createdeh bien, je n'ai pas lu cela de votre question. La lecture des autorisations dépendra dans une certaine mesure de la plate-forme.
Personne ne déménage de SE

1
@Fake Name: Oui, cela supprimera certaines des dépendances de plate-forme, mais certaines plates-formes offrent encore des choses que d'autres n'offrent pas et il n'y a pas de moyen facile de les encapsuler pour toutes. J'ai mis à jour ma réponse, jetez un œil là-bas.
Personne ne quitte le SE

1
Je n'ai aucune idée de la raison pour laquelle cette réponse a été votée. Cela ne vient pas à côté de répondre à la question principale - qui, succinctement, est: "Validez les chemins, s'il vous plaît?" La validation des autorisations de chemin est une question secondaire (et largement ignorée) ici. Bien que l'appel à os.path.exists(filePath)lève techniquement des exceptions sur des chemins non valides, ces exceptions devraient être explicitement interceptées et différenciées des autres exceptions non liées. De plus, le même appel revient Falsesur les chemins existants sur lesquels l'utilisateur actuel n'a pas les autorisations de lecture. En bref, la méchanceté.
Cecil Curry

1
@CecilCurry: Pour répondre à vos questions: Jetez un œil à l'historique d'édition de la question. Comme pour la plupart des questions, ce n'était pas aussi clair au début et même maintenant, le libellé du titre seul pourrait être compris autrement que vous l'avez dit.
Personne ne quitte le SE

9

Avec Python 3, que diriez-vous:

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

Avec l'option «x», nous n'avons pas non plus à nous soucier des conditions de course. Consultez la documentation ici .

Maintenant, cela créera un fichier temporaire de très courte durée s'il n'existe pas déjà - à moins que le nom ne soit invalide. Si vous pouvez vivre avec cela, cela simplifie beaucoup les choses.


2
À ce stade, le projet qui en avait besoin est allé si loin au-delà du point où une réponse est même pertinente que je ne peux pas vraiment accepter une réponse.
Faux nom

Ironiquement, la réponse pratique n'est pas suffisante. Quoi qu'il en soit, je suppose que vous pouviez voir si le fichier existait. Si tel est le cas, essayez de copier le fichier ailleurs, puis essayez de l'écraser.
The Matt

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

va ouvrir le fichier ou donner une erreur s'il n'existe pas. S'il y a une erreur, vous pouvez essayer d'écrire dans le chemin, si vous ne pouvez pas, vous obtenez une deuxième erreur

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

Jetez également un œil ici sur les autorisations sur Windows


1
Pour éviter de devoir explicitement dissocier () le fichier de test, vous pouvez utiliser tempfile.TemporaryFile()qui détruira automatiquement le fichier temporaire lorsqu'il sort de la portée.
D_Bye

@FakeName Le code est différent, j'aurais pu utiliser os.access sur la deuxième partie mais si vous avez suivi le lien que j'ai donné vous auriez vu que ce n'est pas une bonne idée, cela vous laisse la possibilité d'essayer d'ouvrir le chemin d'écriture.
vikki

Je construis mes chemins avec os.path.join, donc je n'ai pas de problèmes d'échappatoire. De plus, je n'ai pas vraiment de problèmes d' autorisation de répertoire . J'ai des problèmes de nom de répertoire (et de nom de fichier) .
Fake Name

@FakeName dans ce cas, il vous suffit d'essayer de l'ouvrir (vous n'avez pas besoin d'écrire), python donne une erreur si le filenamecontient des caractères non valides. J'ai édité la réponse
vikki

1
@HelgaIliashenko L'ouverture en écriture écrasera un fichier existant (le rendra vide) même si vous le fermez immédiatement sans y écrire. C'est pourquoi j'ai commencé à lire en premier car de cette façon, si vous n'obtenez pas d'erreur, vous savez qu'il existe un fichier existant.
vikki

-7

essayez os.path.existsceci vérifiera le chemin et retournera Trues'il existe et Falsesinon.


1
Non. Je dois retourner true si le fichier sur le chemin existe ou peut être créé . Je dois retourner false si le chemin est invalide (en raison de la présence de caractères invalides sur Windows).
Fake Name

quel type de caractère invalide?
Nilesh

Dunno - c'est spécifique à la plate-forme.
Fake Name

2
Spécifique au système de fichiers, en fait.
Piotr Kalinowski
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.