[Python] Comment vérifier si un fichier existe?


Answers

Vous avez la fonction os.path.exists :

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

Cela renvoie True pour les fichiers et les répertoires, mais vous pouvez utiliser os.path.isfile à la os.path.isfile pour tester s'il s'agit d'un fichier spécifique. Il suit les liens symboliques.

Question

Comment voir si un fichier existe ou non, sans utiliser l'instruction try ?




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

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

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

And the doc…

>>> print pox.find.__doc__
find(patterns[,root,recurse,type]); Get path to a file or directory

    patterns: name or partial name string of items to search for
    root: path string of top-level directory to search
    recurse: if True, recurse down from root directory
    type: item filter; one of {None, file, dir, link, socket, block, char}
    verbose: if True, be a little verbose about the search

    On some OS, recursion can be specified by recursion depth (an integer).
    patterns can be specified with basic pattern matching. Additionally,
    multiple patterns can be specified by splitting patterns with a ';'
    For example:
        >>> find('pox*', root='..')
        ['/Users/foo/pox/pox', '/Users/foo/pox/scripts/pox_launcher.py']

        >>> find('*shutils*;*init*')
        ['/Users/foo/pox/pox/shutils.py', '/Users/foo/pox/pox/__init__.py']

>>>

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




Additionally, os.access() :

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

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




Vous pouvez essayer ceci (plus sûr):

try:
    # http://effbot.org/zone/python-with-statement.htm
    # 'with' is safer to open a file
    with open('whatever.txt') as fh:
        # Do something with 'fh'
except IOError as e:
    print("({})".format(e))

La sortie serait:

([Errno 2] Aucun fichier ou répertoire: 'whatever.txt')

Ensuite, en fonction du résultat, votre programme peut continuer à fonctionner à partir de là ou vous pouvez coder pour l'arrêter si vous le souhaitez.




2017/12/22 :

Bien que presque tous les moyens possibles aient été listés dans (au moins une des réponses existantes) (par exemple, des éléments spécifiques à Python 3.4 ont été ajoutés), je vais essayer de tout regrouper.

Note : chaque morceau de code de la bibliothèque standard Python que je vais publier appartient à la version 3.5.3 (les citations doc sont spécifiques à la version 3 ).

Déclaration de problème :

  1. Vérifier le fichier ( discutable : aussi dossier (fichier "spécial")?) Existence
  2. N'utilisez pas les blocs try / except / else / finally

Solutions possibles

  1. [Python]: os.path. exists ( path ) (vérifiez également les autres membres de la famille de fonctions comme os.path.isfile , os.path.isdir , os.path.lexists pour des comportements légèrement différents)

    os.path.exists(path)
    

    Renvoie True si le chemin fait référence à un chemin existant ou à un descripteur de fichier ouvert. Renvoie False pour les liens symboliques brisés. Sur certaines plates-formes, cette fonction peut renvoyer False si l'autorisation d'exécuter os.stat() sur le fichier demandé n'est pas accordée, même si le chemin existe physiquement.

    Tout va bien, mais si vous suivez l'arbre d'importation:

    • os.path - posixpath.py ( ntpath.py )

      • genericpath.py , ligne ~ # 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
        

    c'est juste un try/except block autour de os.stat() os.stat() . Donc, votre code est try/except gratuit, mais plus bas dans le cadrage il y a (au moins) un tel bloc. Cela s'applique également aux autres fonctions ( y compris os.path.isfile ).

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

    • C'est un moyen plus chic (et plus pythonique) de gérer les chemins, mais
    • Sous le capot, il fait exactement la même chose ( pathlib.py , ligne ~ # 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]: avec les gestionnaires de contexte d'instruction . Non plus:

    • Créer une:

      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 ...)
      
      • Et son utilisation - Je vais répliquer le comportement d' isfile (notez que ceci est juste pour démontrer, n'essayez pas d'écrire un tel code pour la production ):

        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
        
    • Utilisez [Python]: contexteLib. supprimer ( * exceptions ) - qui a été spécifiquement conçu pour supprimer sélectivement des exceptions


    Mais, ils semblent être des wrappers sur les blocs try/except/else/finally , comme [Python]: Les états de l' instruction :

    Cela permet d' try commun ... except ... finally les modèles d'utilisation doivent être encapsulés pour une réutilisation pratique.

  3. Fonctions de traversée du système de fichiers (et recherche dans les résultats les éléments correspondants)


    Comme ils parcourent les dossiers, (dans la plupart des cas) ils sont inefficaces pour notre problème (il y a des exceptions, comme le fait de ne pas avoir de caractères génériques - comme l'a souligné @ShadowRanger), donc je ne vais pas insister. Sans oublier que dans certains cas, le traitement du nom de fichier peut être requis.

  4. [Python]: os. access ( chemin, mode, *, dir_fd = Aucun, efficace_ids = False, follow_symlinks = True ) dont le comportement est proche de os.path.exists (en fait c'est plus large, principalement à cause du 2 ème argument)

    • les autorisations utilisateur peuvent restreindre la visibilité du fichier selon les états du document:

      ... tester si l'utilisateur appelant a l'accès spécifié au chemin . le mode devrait être F_OK pour tester l'existence du chemin ...

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

    Puisque je travaille aussi en C , j'utilise aussi cette méthode car sous le capot, elle appelle les API natives (encore une fois, via " $ {PYTHON_SRC_DIR} /Modules/posixmodule.c "), mais elle ouvre aussi une porte pour un utilisateur possible erreurs , et ce n'est pas aussi python que les autres variantes. Donc, comme @AaronHall l'a fait remarquer à juste titre, ne l'utilisez pas à moins de savoir ce que vous faites:

    Remarque : l'appel d' API natives est également possible via [Python]: ctypes - Une bibliothèque de fonctions étrangère pour Python , mais dans la plupart des cas, c'est plus compliqué.

    ( Win spécifique): Comme msvcr * ( vcruntime * ) exporte aussi une famille de fonctions [MSDN]: _access, _waccess , voici un exemple:

    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
    

    Notes :

    • Bien que ce ne soit pas une bonne pratique, j'utilise os.F_OK dans l'appel, mais c'est juste pour plus de clarté (sa valeur est 0 )
    • J'utilise _waccess pour que le même code fonctionne sur Python3 et Python2 (malgré les différences liées à unicode entre eux)
    • Bien que cela cible un domaine très spécifique, il n'a été mentionné dans aucune des réponses précédentes


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

    Notes :

    • Au lieu de coder en dur le chemin de la libc ( "/lib/x86_64-linux-gnu/libc.so.6" ) qui peut (et très probablement, va) varier entre les systèmes, None (ou la chaîne vide) peut être passé au constructeur CDLL ( ctypes.CDLL(None).access(b"/tmp", os.F_OK) ). Selon [homme]: DLOPEN (3) :

      Si filename est NULL, le handle renvoyé est pour le programme principal. Lorsqu'il est donné à dlsym (), ce descripteur provoque la recherche d'un symbole dans le programme principal, suivi de tous les objets partagés chargés au démarrage du programme, puis de tous les objets partagés chargés par dlopen () avec l'indicateur RTLD_GLOBAL .

      • Le programme principal (actuel) ( python ) est lié à la libc , donc ses symboles (y compris l' access ) seront chargés
      • Cela doit être géré avec soin, car des fonctions telles que main , Py_Main et (tous les autres) sont disponibles; les appeler pourrait avoir des effets désastreux (sur le programme actuel)
      • Cela ne s'applique pas aussi à Win (mais ce n'est pas un gros problème, puisque msvcrt.dll se trouve dans "% SystemRoot% \ System32" qui est dans % PATH% par défaut). Je voulais aller plus loin et répliquer ce comportement sur Win (et soumettre un correctif), mais comme il s'avère, la fonction [MSDN]: GetProcAddress ne "voit" que les symboles exportés , donc à moins que quelqu'un déclare les fonctions dans l'exécutable principal comme __declspec(dllexport) (pourquoi la personne ordinaire ferait-elle cela sur Terre?), le programme principal est chargeable mais pratiquement inutilisable
  5. Installez un module tiers avec des fonctionnalités de système de fichiers

    Très probablement, dépendra de l'un des moyens ci-dessus (peut-être avec de légères personnalisations).
    Un exemple serait (encore, spécifique à Win ) [GitHub]: Extensions Python pour Windows (pywin32) , qui est un wrapper Python sur WINAPI .

    Mais, comme cela ressemble plus à une solution de contournement, je m'arrête ici.

  6. Une autre solution de contournement ( lamearie ) est (comme j'aime à l'appeler) l'approche sysadmin : utilisez Python comme un wrapper pour exécuter des commandes shell

    • Gagner :

      (py35x64_test) e:\Work\Dev\\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe\" > nul 2>&1'))"
      0
      
      (py35x64_test) e:\Work\Dev\\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe.notexist\" > nul 2>&1'))"
      1
      
    • Lnx ( Ubtu ):

      [cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp\" > /dev/null 2>&1'))"
      0
      [cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp.notexist\" > /dev/null 2>&1'))"
      512
      

Bottom line :

  • Utilisez les blocs try / except / else / finally , car ils peuvent vous empêcher de tomber dans une série de problèmes désagréables. Un contre-exemple auquel je peux penser est la performance: de tels blocs sont coûteux, alors essayez de ne pas les placer dans le code qu'il est censé exécuter des centaines de milliers de fois par seconde (mais dans la plupart des cas) ce ne sera pas le cas).

Note (s) finale (s) :

  • Je vais essayer de le tenir à jour, toutes les suggestions sont les bienvenues, je vais incorporer tout ce qui sera utile dans la réponse



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

>>> with open('somefile', 'xt') as f: #Using the x-flag, Python3.3 and above
...     f.write('Hello\n')

>>> if not os.path.exists('somefile'): 
...     with open('somefile', 'wt') as f:
...         f.write("Hello\n")
... else:
...     print('File already exists!')



import os
path = /path/to/dir

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

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




Il ne semble pas qu'il y ait une différence fonctionnelle significative entre try / except et isfile() , donc vous devriez utiliser celui qui a du sens.

Si vous voulez lire un fichier, s'il existe, faites

try:
    f = open(filepath)
except IOError:
    print 'Oh dear.'

Mais si vous vouliez simplement renommer un fichier s'il existe, et donc ne pas avoir besoin de l'ouvrir, faites

if os.path.isfile(filepath):
    os.rename(filepath, filepath + '.old')

Si vous voulez écrire dans un fichier, s'il n'existe pas, faites

# python 2
if not os.path.isfile(filepath):
    f = open(filepath, 'w')

# python 3, x opens for exclusive creation, failing if the file already exists
try:
    f = open(filepath, 'wx')
except IOError:
    print 'file already exists'

Si vous avez besoin d'un verrouillage de fichier, c'est une question différente.




You can use the "OS" library of Python:

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



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

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

I hope this is helpful.




import os.path

if os.path.isfile(filepath):



Python 3.4+ dispose d'un module de chemin orienté objet: pathlib . En utilisant ce nouveau module, vous pouvez vérifier si un fichier existe comme ceci:

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

Vous pouvez (et devriez normalement) toujours utiliser un bloc try/except lors de l'ouverture des fichiers:

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

Le module pathlib contient plein de trucs sympas: globbing pratique, vérification du propriétaire du fichier, facilité de connexion, etc. Si vous utilisez un ancien Python (version 2.6 ou ultérieure), vous pouvez toujours installer pathlib avec pip:

# installs pathlib2 on older Python versions
# the original third-party module, pathlib, is no longer maintained.
pip install pathlib2

Puis importez-le comme suit:

# Older Python versions
import pathlib2 as pathlib



import os
#Your path here e.g. "C:\Program Files\text.txt"
#For access purposes: "C:\\Program Files\\text.txt"
if os.path.exists("C:\..."):   
    print "File found!"
else:
    print "File not found!"

L'importation facilite la navigation et l'exécution d'actions standard avec votre système d'exploitation.

Pour plus d'informations, voir share

Si vous avez besoin d'opérations de haut niveau, utilisez shutil .




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

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

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




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



Links