Come posso verificare se esiste un file senza eccezioni?


Risposte:


5154

Se il motivo che stai verificando è che puoi fare qualcosa del genere if file_exists: open_it(), è più sicuro usare un tryaround nel tentativo di aprirlo. Il controllo e quindi l'apertura comporta il rischio che il file venga eliminato o spostato o qualcosa tra il momento del controllo e il momento in cui si tenta di aprirlo.

Se non hai intenzione di aprire immediatamente il file, puoi usarlo os.path.isfile

Restituisce Truese il percorso è un file normale esistente. Questo segue collegamenti simbolici, quindi sia islink () che isfile () possono essere veri per lo stesso percorso.

import os.path
os.path.isfile(fname) 

se devi assicurarti che sia un file.

A partire da Python 3.4, il pathlibmodulo offre un approccio orientato agli oggetti (con backport pathlib2in Python 2.7):

from pathlib import Path

my_file = Path("/path/to/file")
if my_file.is_file():
    # file exists

Per controllare una directory, eseguire:

if my_file.is_dir():
    # directory exists

Per verificare se Pathesiste un oggetto indipendentemente dal fatto che si tratti di un file o di una directory, utilizzare exists():

if my_file.exists():
    # path exists

Puoi anche usare resolve(strict=True)in un tryblocco:

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

40
riguardo alla prima osservazione (usa "prova" se controlla prima di aprire) sfortunatamente questo non funzionerà se vuoi aprirlo per accodarti assicurandoti che esista prima dato che la modalità 'a' creerà se non esiste.
Makapuf,

6
Si noti che FileNotFoundErrorè stato introdotto in Python 3. Se hai bisogno anche di supportare Python 2.7 e Python 3, è possibile utilizzare IOErrorinvece (che FileNotFoundErrorsottoclassi) stackoverflow.com/a/21368457/1960959
scottclowe

7
@makapuf Puoi aprirlo per "aggiornamento" ( open('file', 'r+')) e poi cercare fino alla fine.
kyrill,

2111

Hai la os.path.existsfunzione:

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

Questo ritorna Truesia per i file che per le directory ma puoi invece usarli

os.path.isfile(file_path)

per verificare se si tratta di un file in particolare. Segue symlink.


966

A differenza isfile(), exists()tornerà Trueper le directory. Quindi, a seconda se vuoi solo file semplici o anche directory, utilizzerai isfile()o exists(). Ecco alcuni semplici output REPL:

>>> os.path.isfile("/etc/password.txt")
True
>>> os.path.isfile("/etc")
False
>>> os.path.isfile("/does/not/exist")
False
>>> os.path.exists("/etc/password.txt")
True
>>> os.path.exists("/etc")
True
>>> os.path.exists("/does/not/exist")
False

623
import os.path

if os.path.isfile(filepath):

320

Utilizzare os.path.isfile()con os.access():

import os

PATH = './file.txt'
if os.path.isfile(PATH) and os.access(PATH, os.R_OK):
    print("File exists and is readable")
else:
    print("Either the file is missing or not readable")

60
avere più condizioni, alcune delle quali superflue, è meno chiara ed esplicita.
mercoledì

10
È inoltre ridondante. Se il file non esiste, os.access()restituirà false.
Marchese di Lorne,

9
@EJP In file linux possono esistere ma non sono accessibili.
e-info128,

8
poiché tu import os, non è necessario di import os.pathnuovo in quanto è già parte di os. Devi solo importare os.pathse intendi utilizzare solo le funzioni da os.pathe non da osse stesso, per importare una cosa più piccola, ma mentre usi os.accesse os.R_OKnon è necessaria la seconda importazione.
Giullare

287
import os
os.path.exists(path) # Returns whether the path (directory or file) exists or not
os.path.isfile(path) # Returns whether the file exists or not

2
Generalmente, non è una buona pratica assegnare nomi alle variabili come i nomi dei metodi.
Homunculus Reticulli,

245

Sebbene quasi tutti i modi possibili siano stati elencati in (almeno una delle) risposte esistenti (ad esempio , è stato aggiunto materiale specifico per Python 3.4 ), cercherò di raggruppare tutto insieme.

Nota : ogni pezzo di codice di libreria standard Python che sto per pubblicare, appartiene alla versione 3.5.3 .

Dichiarazione del problema :

  1. Controlla l' esistenza del file ( discutibile : anche cartella (file "speciale")?)
  2. Non usare i blocchi try / tranne / else / finally

Possibili soluzioni :

  1. [Python 3]: os.path. esiste ( percorso ) (controllare anche altri membri della famiglia come funzione os.path.isfile, os.path.isdir, os.path.lexistsper leggermente diversi comportamenti)

    os.path.exists(path)

    Restituisce Truese percorso fa riferimento a un percorso esistente o a un descrittore di file aperto. Restituisce Falseper collegamenti simbolici interrotti. Su alcune piattaforme, questa funzione può restituire Falsese non è stata concessa l'autorizzazione per eseguire os.stat () sul file richiesto, anche se il percorso esiste fisicamente.

    Tutto bene, ma se segue l'albero di importazione:

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

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

    è solo un blocco try / tranne intorno a [Python 3]: os. stat ( path, *, dir_fd = None, follow_symlinks = True ) . Quindi, il tuo codice è try / tranne gratuito, ma più in basso nel framestack c'è (almeno) uno di questi blocchi. Questo vale anche per altre funzioni ( incluso os.path.isfile ).

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

    • È un modo più elaborato (e più di Python Ic) di gestire i percorsi, ma
    • Sotto il cofano, fa esattamente la stessa cosa ( pathlib.py , line ~ # 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 3]: con i gestori di contesto delle istruzioni . O:

    • Crearne uno:

      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 ...)
      • E il suo utilizzo: replicherò il os.path.isfilecomportamento (si noti che questo è solo a scopo dimostrativo, non tentare di scrivere tale codice per la produzione ):

        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
    • Usa [Python 3]: contextlib. sopprimere ( * eccezioni ) - che è stato specificamente progettato per sopprimere selettivamente le eccezioni


    Ma sembrano essere wrapper per i blocchi try / tranne / else / finally , come [Python 3]: L' istruzione with afferma:

    Ciò consente un tentativo comune ... tranne ... infine i modelli di utilizzo da incapsulare per un comodo riutilizzo.

  3. Funzioni di attraversamento del filesystem (e ricerca i risultati per gli articoli corrispondenti)


    Dal momento che questi ripetono le cartelle, (nella maggior parte dei casi) sono inefficienti per il nostro problema (ci sono eccezioni, come glob bing non jolly - come sottolineato da @ShadowRanger), quindi non ho intenzione di insistere su di loro. Per non parlare del fatto che in alcuni casi potrebbe essere necessaria l'elaborazione del nome file.

  4. [Python 3]: os. accesso ( percorso, modalità, *, dir_fd = None, effective_ids = false, follow_symlinks = true ) il cui comportamento è vicino a os.path.exists(in realtà è più ampio, soprattutto a causa della 2 ° argomento)

    • le autorizzazioni dell'utente potrebbero limitare la "visibilità" del file come afferma il documento:

      ... verifica se l'utente che ha invocato ha l'accesso specificato al percorso . la modalità dovrebbe essere F_OK per testare l'esistenza del percorso ...

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

    Dal momento che anche il lavoro in C , io uso questo metodo anche perché sotto il cofano, chiama nativo API s (di nuovo, tramite "$ {} PYTHON_SRC_DIR /Modules/posixmodule.c" ), ma apre anche una porta per un possibile uso errori , e non è come Python ic come altre varianti. Quindi, come ha giustamente sottolineato @AaronHall, non usarlo a meno che tu non sappia cosa stai facendo:

    Nota : è anche possibile chiamare API native tramite [Python 3]: ctypes - Una libreria di funzioni esterne per Python , ma nella maggior parte dei casi è più complicata.

    ( Specifico per Win ): poiché vcruntime * ( msvcr * ) .dll esporta un [MS.Docs]: _access, _waccess, anche una famiglia di funzioni, ecco un esempio:

    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.notexist", os.F_OK)
    -1

    Note :

    • Sebbene non sia una buona pratica, sto usando os.F_OKla chiamata, ma è solo per chiarezza (il suo valore è 0 )
    • Sto utilizzando _waccess in modo che le stesse opere di codice su python3 e python2 (nonostante unicode legati differenze tra di loro)
    • Sebbene questo abbia come obiettivo un'area molto specifica, non è stato menzionato in nessuna delle risposte precedenti


    Anche la controparte 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"/tmp.notexist", os.F_OK)
    -1

    Note :

    • Invece il percorso di libc hardcoding ( "/lib/x86_64-linux-gnu/libc.so.6" ) che può (e molto probabilmente, varierà) tra i sistemi, None (o la stringa vuota) può essere passato al costruttore CDLL ( ctypes.CDLL(None).access(b"/tmp", os.F_OK)). Secondo [man7]: DLOPEN (3) :

      Se il nome file è NULL, l'handle restituito è per il programma principale. Se assegnato a dlsym (), questo handle provoca la ricerca di un simbolo nel programma principale, seguito da tutti gli oggetti condivisi caricati all'avvio del programma e quindi da tutti gli oggetti condivisi caricati da dlopen () con il flag RTLD_GLOBAL .

      • Il programma (attuale) principale ( python ) è collegato a libc , quindi i suoi simboli (incluso l' accesso ) verranno caricati
      • Questo deve essere gestito con cura, poiché sono disponibili funzioni come main , Py_Main e (tutte le altre); chiamarli potrebbe avere effetti disastrosi (sul programma attuale)
      • Questo non si applica anche a Win (ma non è un grosso problema, poiché msvcrt.dll si trova in "% SystemRoot% \ System32" che è in % PATH% per impostazione predefinita). Volevo andare oltre e replicare questo comportamento su Win (e inviare una patch), ma come risulta, [MS.Docs]: la funzione GetProcAddress "vede" solo i simboli esportati , quindi a meno che qualcuno non dichiari le funzioni nell'eseguibile principale come __declspec(dllexport)(perché sulla Terra la persona normale dovrebbe farlo?), il programma principale è caricabile ma praticamente inutilizzabile
  5. Installa alcuni moduli di terze parti con funzionalità di filesystem

    Molto probabilmente, si baserà su uno dei modi sopra (forse con lievi personalizzazioni).
    Un esempio potrebbe essere (di nuovo, specifico di Win ) [GitHub]: mhammond / pywin32 - Estensioni Python per Windows (pywin32) , che è un wrapper Python su WINAPI .

    Ma, dato che è più una soluzione alternativa, mi fermo qui.

  6. Un altro (lame) soluzione alternativa ( gainarie ) è (come mi piace chiamarlo) l' approccio sysadmin : usare Python come wrapper per eseguire comandi shell

    • Vincere :

      (py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe\" > nul 2>&1'))"
      0
      
      (py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe.notexist\" > nul 2>&1'))"
      1
    • Nix ( 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

Linea di fondo :

  • Fare uso try / tranne / altro / infine blocchi, perché possono impedire di incorrere in una serie di problemi di brutto. Un contro-esempio a cui riesco a pensare è la prestazione: tali blocchi sono costosi, quindi cerca di non inserirli nel codice che dovrebbe essere eseguito centinaia di migliaia di volte al secondo (ma poiché (nella maggior parte dei casi) comporta l'accesso al disco, non sarà il caso).

Note finali :

  • Cercherò di tenerlo aggiornato, eventuali suggerimenti sono ben accetti, includerò tutto ciò che sarà utile nella risposta

3
Puoi approfondire questa affermazione? "Anche se non è una buona pratica, sto usando os.F_OK nella chiamata, ma è solo per chiarezza (il suo valore è 0)"
sk8asd123,

6
@ sk8asd123: Un po 'difficile farlo in un commento: in generale, è meglio usare costanti con funzioni con cui si uniscono. Questo vale quando si lavora con più moduli che definiscono la stessa costante, perché alcuni potrebbero non essere aggiornati ed è meglio che le funzioni e le costanti siano sincronizzate. Quando lavoro con i tipi (chiamando direttamente le funzioni) avrei dovuto definire la costante (da MSDN ), o non usare affatto una costante. È solo una linea guida che uso, nel 99,9% probabilmente non fa alcuna differenza (dal punto di vista funzionale).
CristiFati,

3
@CristiFati: A partire da 3.6, glob.iglob(e glob.globpure) sono basatios.scandir , quindi ora è pigro; per ottenere il primo hit in una directory di file 10M, scansiona solo fino a raggiungere il primo hit. E anche pre-3.6, se usi globmetodi senza jolly, la funzione è intelligente: sa che puoi avere solo un colpo, quindi semplifica il globbing a solo os.path.isdiroos.path.lexists (a seconda che il percorso finisca /).
ShadowRanger,

3
Quella seconda parte del mio commento (globbing senza caratteri jolly non esegue l'iterazione della cartella e non l'ha mai fatto) significa che è una soluzione perfettamente efficiente al problema (più lenta della chiamata diretta os.path.isdiro os.path.lexistpoiché è un gruppo di chiamate e stringhe di funzioni a livello di Python operazioni prima che decida che il percorso efficiente è praticabile, ma nessuna chiamata di sistema aggiuntiva o lavoro I / O, che è più lento degli ordini di grandezza).
ShadowRanger,

154

Questo è il modo più semplice per verificare l'esistenza di un file. Solo perché il file esisteva quando hai controllato non garantisce che sarà lì quando è necessario aprirlo.

import os
fname = "foo.txt"
if os.path.isfile(fname):
    print("file does exist at this time")
else:
    print("no such file exists at this time")

17
Finché si intende accedere al file, esiste la condizione di competizione , indipendentemente da come è stato costruito il programma. Il tuo programma non può garantire che un altro processo sul computer non abbia modificato il file. È ciò che Eric Lippert definisce un'eccezione esogena . Non puoi evitarlo controllando prima l'esistenza del file.
Isaac Supeene,

@IsaacSupeene La migliore pratica è rendere la finestra dell'operazione (file) il più piccola possibile seguita da una corretta gestione delle eccezioni
un33k

145

Python 3.4+ ha un modulo path orientato agli oggetti: pathlib . Utilizzando questo nuovo modulo, puoi verificare se esiste un file in questo modo:

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

Puoi (e di solito dovresti) usare ancora un try/exceptblocco quando apri i file:

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

Il modulo pathlib ha un sacco di cose interessanti in esso: comodo globbing, controllo del proprietario del file, accesso più semplice al percorso, ecc. Vale la pena dare un'occhiata. Se utilizzi un Python precedente (versione 2.6 o successiva), puoi comunque installare pathlib con pip:

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

Quindi importalo come segue:

# Older Python versions
import pathlib2 as pathlib

124

Preferisci l'istruzione try. È considerato uno stile migliore ed evita le condizioni di gara.

Non crederci sulla parola. C'è molto supporto per questa teoria. Eccone un paio:


3
Aggiungi fonti migliori per supportare la tua dichiarazione.
BlueTrin,

11
Il link citato Evitando le condizioni di gara (supporto per apple dev) non supporta la tua risposta. Riguarda solo l'uso di file temporanei che contengono informazioni riservate su sistemi operativi mal progettati che non eseguono correttamente il sandbox di file / directory temporanei tramite autorizzazioni limitate. L'uso try...exceptnon aiuta comunque a risolvere questo problema.
jstine,

Il problema con questo metodo è che se si dispone di un pezzo di codice importante a seconda del file inesistente, inserendolo nella except:clausola si farà in modo che un'eccezione derivante da questa parte del codice genererà un messaggio confuso (secondo errore generato durante l'elaborazione del primo.)
Camion

119

Come posso verificare se esiste un file, usando Python, senza usare un'istruzione try?

Ora disponibile da Python 3.4, importa e crea un'istanza di un Pathoggetto con il nome del file e controlla il is_filemetodo (nota che questo restituisce True anche per i collegamenti simbolici che puntano a file regolari):

>>> from pathlib import Path
>>> Path('/').is_file()
False
>>> Path('/initrd.img').is_file()
True
>>> Path('/doesnotexist').is_file()
False

Se sei su Python 2, puoi eseguire il backport del modulo pathlib da pypi pathlib2, oppure controllare isfiledal os.pathmodulo:

>>> import os
>>> os.path.isfile('/')
False
>>> os.path.isfile('/initrd.img')
True
>>> os.path.isfile('/doesnotexist')
False

Ora quanto sopra è probabilmente la migliore risposta diretta pragmatica qui, ma c'è la possibilità di una condizione di competizione (a seconda di ciò che stai cercando di realizzare) e il fatto che l'implementazione sottostante usi un try, ma Python usa tryovunque nella sua implementazione.

Poiché Python utilizza tryovunque, non c'è davvero alcun motivo per evitare un'implementazione che lo utilizza.

Ma il resto di questa risposta tenta di considerare questi avvertimenti.

Risposta più lunga, molto più pedante

Disponibile da Python 3.4, usa il nuovo Pathoggetto in pathlib. Nota che .existsnon è del tutto corretto, perché le directory non sono file (tranne nel senso unix che tutto è un file).

>>> from pathlib import Path
>>> root = Path('/')
>>> root.exists()
True

Quindi dobbiamo usare is_file:

>>> root.is_file()
False

Ecco l'aiuto su is_file:

is_file(self)
    Whether this path is a regular file (also True for symlinks pointing
    to regular files).

Quindi otteniamo un file che sappiamo essere un file:

>>> import tempfile
>>> file = tempfile.NamedTemporaryFile()
>>> filepathobj = Path(file.name)
>>> filepathobj.is_file()
True
>>> filepathobj.exists()
True

Per impostazione predefinita, NamedTemporaryFileelimina il file quando viene chiuso (e si chiuderà automaticamente quando non vi sono più riferimenti).

>>> del file
>>> filepathobj.exists()
False
>>> filepathobj.is_file()
False

Se approfondisci l'implementazione , vedrai che is_fileutilizza try:

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

Condizioni di gara: perché ci piace provare

Ci piace tryperché evita le condizioni di gara. Con try, semplicemente provi a leggere il tuo file, aspettandoti che sia lì e, in caso contrario, catturi l'eccezione ed esegui qualunque comportamento di fallback abbia senso.

Se si desidera verificare l'esistenza di un file prima di tentare di leggerlo, è possibile che lo si stia eliminando e quindi si stiano utilizzando più thread o processi oppure un altro programma sia a conoscenza di quel file e possa eliminarlo - si rischia la possibilità di una condizione di gara se la controlli esiste, perché stai quindi correndo per aprirla prima che le sue condizioni (la sua esistenza) cambino.

Le condizioni di gara sono molto difficili da debug perché c'è una finestra molto piccola in cui possono far fallire il tuo programma.

Ma se questa è la tua motivazione, puoi ottenere il valore di una trydichiarazione usando il suppressgestore di contesto.

Evitare le condizioni di gara senza una dichiarazione di prova: suppress

Python 3.4 ci fornisce il suppressgestore del contesto (in precedenza il ignoregestore del contesto), che fa semanticamente esattamente la stessa cosa in meno righe, mentre anche (almeno superficialmente) incontrando l'originale chiede di evitare una trydichiarazione:

from contextlib import suppress
from pathlib import Path

Uso:

>>> with suppress(OSError), Path('doesnotexist').open() as f:
...     for line in f:
...         print(line)
... 
>>>
>>> with suppress(OSError):
...     Path('doesnotexist').unlink()
... 
>>> 

Per i precedenti Pythons, potresti ottenere il tuo suppress, ma senza un trysarà più dettagliato che con. Credo che questa sia in realtà l'unica risposta che non viene utilizzata trya nessun livello in Python a cui può essere applicata prima di Python 3.4 perché utilizza invece un gestore di contesto:

class suppress(object):
    def __init__(self, *exceptions):
        self.exceptions = exceptions
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            return issubclass(exc_type, self.exceptions)

Forse più facile con una prova:

from contextlib import contextmanager

@contextmanager
def suppress(*exceptions):
    try:
        yield
    except exceptions:
        pass

Altre opzioni che non soddisfano la richiesta di "senza provare":

isfile

import os
os.path.isfile(path)

dai documenti :

os.path.isfile(path)

Restituisce True se il percorso è un file normale esistente. Questo segue collegamenti simbolici, quindi entrambi islink()e isfile()possono essere veri per lo stesso percorso.

Ma se si esamina l' origine di questa funzione, si vedrà che effettivamente utilizza un'istruzione try:

# This follows symbolic links, so both islink() and isdir() can be true
# for the same path on systems that support symlinks
def isfile(path):
    """Test whether a path is a regular file"""
    try:
        st = os.stat(path)
    except os.error:
        return False
    return stat.S_ISREG(st.st_mode)
>>> OSError is os.error
True

Tutto ciò che sta facendo è utilizzare il percorso indicato per vedere se è possibile ottenere statistiche su di esso, catturare OSErrore quindi verificare se si tratta di un file se non ha sollevato l'eccezione.

Se hai intenzione di fare qualcosa con il file, ti suggerirei di provarlo direttamente con un tentativo, tranne per evitare una condizione di competizione:

try:
    with open(path) as f:
        f.read()
except OSError:
    pass

os.access

Disponibile per Unix e Windows è os.access, ma per usare è necessario passare i flag e non fa distinzione tra file e directory. Questo è più usato per verificare se l'utente che ha effettivamente invocato ha accesso in un ambiente con privilegi elevati:

import os
os.access(path, os.F_OK)

Soffre anche degli stessi problemi di razza isfile. Dai documenti :

Nota: l'uso di access () per verificare se un utente è autorizzato ad es. Ad aprire un file prima di farlo effettivamente utilizzando open () crea una falla di sicurezza, poiché l'utente potrebbe sfruttare l'intervallo di tempo breve tra il controllo e l'apertura del file per manipolarlo. È preferibile utilizzare le tecniche EAFP. Per esempio:

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

è meglio scritto come:

try:
    fp = open("myfile")
except IOError as e:
    if e.errno == errno.EACCES:
        return "some default data"
    # Not a permission error.
    raise
else:
    with fp:
        return fp.read()

Evitare l'uso os.access. È una funzione di basso livello che ha più opportunità di errore dell'utente rispetto agli oggetti e alle funzioni di livello superiore discussi sopra.

Critica per un'altra risposta:

Un'altra risposta dice questo su os.access:

Personalmente, preferisco questo perché sotto il cofano, chiama API native (tramite "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), ma apre anche una porta per possibili errori dell'utente e non è così Pythonic come altre varianti :

Questa risposta afferma che preferisce un metodo non Pythonic, soggetto a errori, senza giustificazione. Sembra incoraggiare gli utenti a utilizzare API di basso livello senza capirle.

Crea anche un gestore di contesto che, ritornando incondizionatamente True, consente a tutte le Eccezioni (incluso KeyboardInterrupte SystemExit!) Di passare silenziosamente, il che è un buon modo per nascondere i bug.

Ciò sembra incoraggiare gli utenti ad adottare pratiche inadeguate.


87
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'importazione ossemplifica la navigazione e l'esecuzione di azioni standard con il tuo sistema operativo.

Per riferimento vedi anche Come verificare se esiste un file usando Python?

Se sono necessarie operazioni di alto livello, utilizzare shutil.


9
Questa risposta è sbagliata os.path.existsritorna vero per cose che non sono file, come le directory. Questo dà falsi positivi. Vedi le altre risposte che raccomandano os.path.isfile.
Chris Johnson,

84

Test per file e cartelle con os.path.isfile(), os.path.isdir()eos.path.exists()

Supponendo che il "percorso" sia un percorso valido, questa tabella mostra ciò che viene restituito da ciascuna funzione per file e cartelle:

inserisci qui la descrizione dell'immagine

Puoi anche verificare se un file è un determinato tipo di file usando os.path.splitext()per ottenere l'estensione (se non lo conosci già)

>>> import os
>>> path = "path to a word document"
>>> os.path.isfile(path)
True
>>> os.path.splitext(path)[1] == ".docx" # test if the extension is .docx
True

72

Nel 2016 il modo migliore sta ancora usando os.path.isfile:

>>> os.path.isfile('/path/to/some/file.txt')

O in Python 3 puoi usare pathlib:

import pathlib
path = pathlib.Path('/path/to/some/file.txt')
if path.is_file():
    ...

3
Posso chiederti: qual è il vantaggio di usare il modulo 'pathlib' invece del modulo 'os' in python3 per questo controllo?
Joko,

3
pathlibè la soluzione OOP di Python per i percorsi. Puoi fare molto di più con esso. Se hai solo bisogno di controllare l'esistenza, il vantaggio non è così grande.
KaiBuxe,

65

Non sembra che ci sia una differenza funzionale significativa tra try / tranne e isfile(), quindi dovresti usare quale ha senso.

Se vuoi leggere un file, se esiste, fallo

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

Ma se vuoi solo rinominare un file se esiste, e quindi non è necessario aprirlo, fallo

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

Se vuoi scrivere su un file, se non esiste, fallo

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

Se hai bisogno di bloccare i file, è una questione diversa.


3
Questa risposta è sbagliata os.path.existsritorna vero per cose che non sono file, come le directory. Questo dà falsi positivi. Vedi le altre risposte che raccomandano os.path.isfile.
Chris Johnson,

6
Nel tuo terzo esempio, creo un collegamento denominato filepathcon il tempismo giusto e , BAM , sovrascrivi il file di destinazione. Dovresti farlo open(filepath, 'wx')in un try...exceptblocco per evitare il problema.
extra

1
Nel tuo secondo esempio, almeno in Windows, otterrai un OSErrorse filepath + '.old'esiste già: "Su Windows, se dst esiste già, OSError verrà generato anche se si tratta di un file; potrebbe non esserci modo di implementare una ridenominazione atomica quando dst nomina un file esistente. "
Tom Myddeltyn,

@TomMyddeltyn: A partire da Python 3.3,os.replace esegue in modo portabile la sostituzione silenziosa del file di destinazione (è identico al os.renamecomportamento di Linux) (solo errori se il nome di destinazione esiste ed è una directory). Quindi sei bloccato su 2.x, ma gli utenti di Py3 hanno avuto una buona opzione per diversi anni.
ShadowRanger,

Sul renameEsempio: Si deve ancora essere fatto con try/ except. os.rename(o os.replacesu Python moderno) è atomico; farlo controllare e poi rinominare introduce una corsa non necessaria e chiamate di sistema aggiuntive. Basta faretry: os.replace(filepath, filepath + '.old') except OSError: pass
ShadowRanger il

59

Potresti provare questo (più sicuro):

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

L'uscita sarebbe:

([Errno 2] Nessun file o directory di questo tipo: 'whatever.txt')

Quindi, a seconda del risultato, il tuo programma può continuare a funzionare da lì o puoi programmare per fermarlo se vuoi.


18
La domanda iniziale chiesto una soluzione che non utilizzatry
RRS

5
Questa risposta manca il punto del PO. Controllare che esista un file non equivale a verificare se è possibile aprirlo. Ci saranno casi in cui esiste un file ma per una serie di motivi, non è possibile aprirlo.
Chris Johnson,

51

Anche se consiglio sempre di usare trye le exceptdichiarazioni, ecco alcune possibilità per te (il mio preferito personale sta usando os.access):

  1. Prova ad aprire il file:

    L'apertura del file verificherà sempre l'esistenza del file. Puoi fare una funzione in questo modo:

    def File_Existence(filepath):
        f = open(filepath)
        return True

    Se è False, interromperà l'esecuzione con un IOError o OSError non gestito nelle versioni successive di Python. Per catturare l'eccezione, devi usare una clausola try tranne. Ovviamente, puoi sempre usare tryun'istruzione etc in questo modo (grazie a hsandt per avermi fatto pensare):

    def File_Existence(filepath):
        try:
            f = open(filepath)
        except IOError, OSError: # Note OSError is for later versions of Python
            return False
    
        return True
  2. Utilizzare os.path.exists(path):

    Questo verificherà l'esistenza di ciò che specifichi. Tuttavia, verifica la presenza di file e directory, quindi fai attenzione a come lo usi.

    import os.path
    >>> os.path.exists("this/is/a/directory")
    True
    >>> os.path.exists("this/is/a/file.txt")
    True
    >>> os.path.exists("not/a/directory")
    False
  3. Utilizzare os.access(path, mode):

    Questo verificherà se hai accesso al file. Controllerà le autorizzazioni. Sulla base della documentazione os.py, digitando os.F_OK, verificherà l'esistenza del percorso. Tuttavia, l'utilizzo di questo creerà un buco nella sicurezza, in quanto qualcuno può attaccare il tuo file usando il tempo tra il controllo delle autorizzazioni e l'apertura del file. Dovresti invece andare direttamente all'apertura del file invece di controllarne le autorizzazioni. ( EAFP vs LBYP ). Se non aprirai il file in un secondo momento e ne controllerai solo l'esistenza, puoi usarlo.

    Comunque, qui:

    >>> import os
    >>> os.access("/is/a/file.txt", os.F_OK)
    True

Dovrei anche menzionare che ci sono due modi in cui non sarai in grado di verificare l'esistenza di un file. O il problema sarà permission deniedo no such file or directory. Se ne prendi uno IOError, imposta IOError as e(come la mia prima opzione), quindi digita in print(e.args)modo da poter sperare di determinare il problema. Spero possa essere d'aiuto! :)


51

Data: 2017/12/04

Ogni possibile soluzione è stata elencata in altre risposte.

Un modo intuitivo e discutibile per verificare l'esistenza di un file è il seguente:

import os
os.path.isfile('~/file.md')  # Returns True if exists, else False
# additionaly check a dir
os.path.isdir('~/folder')  # Returns True if the folder exists, else False
# check either a dir or a file
os.path.exists('~/file')

Ho creato un completo cheatsheet per il tuo riferimento:

#os.path methods in exhaustive cheatsheet
{'definition': ['dirname',
               'basename',
               'abspath',
               'relpath',
               'commonpath',
               'normpath',
               'realpath'],
'operation': ['split', 'splitdrive', 'splitext',
               'join', 'normcase'],
'compare': ['samefile', 'sameopenfile', 'samestat'],
'condition': ['isdir',
              'isfile',
              'exists',
              'lexists'
              'islink',
              'isabs',
              'ismount',],
 'expand': ['expanduser',
            'expandvars'],
 'stat': ['getatime', 'getctime', 'getmtime',
          'getsize']}

37

Se il file è per l'apertura, è possibile utilizzare una delle seguenti tecniche:

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!')

AGGIORNARE

Solo per evitare confusione e in base alle risposte che ho ricevuto, la risposta corrente trova un file o una directory con il nome dato.


9
Questa risposta è sbagliata os.path.existsritorna vero per cose che non sono file, come le directory. Questo dà falsi positivi. Vedi le altre risposte che raccomandano os.path.isfile.
Chris Johnson,

anche il problema dei falsi positivi.
Zorglub29,

docs.python.org/3/library/os.path.html#os.path.exists Alla precedente affermazione di chris >> os.path.exists (percorso)> Restituisce True se path fa riferimento a un percorso esistente o aperto descrittore di file. Restituisce False per collegamenti simbolici interrotti. Su alcune piattaforme, questa funzione può restituire False se non viene concessa l'autorizzazione per eseguire os.stat () sul file richiesto, anche se il percorso esiste fisicamente. Modificato nella versione 3.3: il percorso può ora essere un numero intero: True viene restituito se si tratta di un descrittore di file aperto, False altrimenti. Modificato nella versione 3.6: accetta un oggetto simile a un percorso.
JayRizzo,

36

Inoltre, os.access():

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

Essere R_OK, W_OKe X_OKle bandiere per verificare le autorizzazioni ( doc ).


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

Sollevare le eccezioni è considerato un approccio accettabile e Pythonic per il controllo del flusso nel programma. Prendi in considerazione la gestione dei file mancanti con IOErrors. In questa situazione, verrà sollevata un'eccezione IOError se il file esiste ma l'utente non dispone delle autorizzazioni di lettura.

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


3
L'OP ha chiesto come verificare se esiste un file. È possibile che esista un file ma che tu non riesca ad aprirlo. Pertanto l'utilizzo dell'apertura di un file come proxy per verificare se il file esiste non è corretto: avrà falsi negativi.
Chris Johnson,

19

Se hai importato NumPy già per altri scopi, allora non c'è bisogno di importare altre librerie come pathlib, os, paths, etc.

import numpy as np
np.DataSource().exists("path/to/your/file")

Ciò restituirà vero o falso in base alla sua esistenza.


18

Puoi scrivere il suggerimento di Brian senza il try:.

from contextlib import suppress

with suppress(IOError), open('filename'):
    process()

suppressfa parte di Python 3.4. Nelle versioni precedenti puoi scrivere rapidamente il tuo soppressore:

from contextlib import contextmanager

@contextmanager
def suppress(*exceptions):
    try:
        yield
    except exceptions:
        pass

17

Sono l'autore di un pacchetto che esiste da circa 10 anni e ha una funzione che risponde direttamente a questa domanda. Fondamentalmente, se ci si trova su un sistema non Windows, utilizza Popenper accedere find. Tuttavia, se sei su Windows, si replica findcon un efficiente walker del filesystem.

Il codice stesso non usa un tryblocco ... tranne che per determinare il sistema operativo e quindi indirizzarti allo stile "Unix" findo al buillt manuale find. I test di temporizzazione hanno dimostrato che tryera più veloce nel determinare il sistema operativo, quindi ne ho usato uno lì (ma da nessun'altra parte).

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

E il 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']

>>>

L'implementazione, se ti interessa guardare, è qui: https://github.com/uqfoundation/pox/blob/89f90fb308f285ca7a62eabe2c38acb87e89dad9/pox/shutils.py#L190


17

Verifica l'esistenza di file o directory

Puoi seguire questi tre modi:

Nota 1: os.path.isfileutilizzato solo per i file

import os.path
os.path.isfile(filename) # True if file exists
os.path.isfile(dirname) # False if directory exists

Nota2: os.path.existsutilizzato per file e directory

import os.path
os.path.exists(filename) # True if file exists
os.path.exists(dirname) #True if directory exists

Il pathlib.Pathmetodo (incluso in Python 3+, installabile con pip per Python 2)

from pathlib import Path
Path(filename).exists()

16

Aggiungendo un'altra leggera variazione che non si riflette esattamente nelle altre risposte.

Questo gestirà il caso file_pathdell'essere Noneo della stringa vuota.

def file_exists(file_path):
    if not file_path:
        return False
    elif not os.path.isfile(file_path):
        return False
    else:
        return True

Aggiunta di una variante basata sul suggerimento di Shahbaz

def file_exists(file_path):
    if not file_path:
        return False
    else:
        return os.path.isfile(file_path)

Aggiunta di una variante basata sul suggerimento di Peter Wood

def file_exists(file_path):
    return file_path and os.path.isfile(file_path):

3
if (x) return true; else return false;è davvero giusto return x. Le tue ultime quattro righe possono diventare return os.path.isfile(file_path). Mentre ci siamo, l'intera funzione può essere semplificata come return file_path and os.path.isfile(file_path).
Shahbaz,

Devi stare attento con return xnel caso di if (x). Python considererà una stringa vuota False, nel qual caso restituiremmo una stringa vuota anziché un valore bool. Lo scopo di questa funzione è di restituire sempre il bool.
Marcel Wilson,

1
Vero. In questo caso, tuttavia, xè os.path.isfile(..)così è già bool.
Shahbaz,

os.path.isfile(None)solleva un'eccezione, motivo per cui ho aggiunto il controllo if. Probabilmente potrei semplicemente avvolgerlo in un tentativo / tranne invece, ma ho sentito che era più esplicito in questo modo.
Marcel Wilson,

3
return file_path and os.path.isfile(file_path)
Peter Wood,

15

Ecco un comando Python a 1 riga per l'ambiente della riga di comando di Linux. Lo trovo MOLTO COMODO dal momento che non sono un ragazzo Bash così caldo.

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

Spero che questo sia utile.


6
Controllo di una riga in bash: [ -f "${file}" ] && echo "file found" || echo "file not found"(che è lo stesso di if [ ... ]; then ...; else ...; fi).
flotzilla,

12

Puoi usare la libreria "OS" di Python:

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

5
Questa risposta è sbagliata os.path.existsritorna vero per cose che non sono file, come le directory. Questo dà falsi positivi. Vedi le altre risposte che raccomandano os.path.isfile.
Chris Johnson,

La funzione @Chris Johnson, os.path.exists () controlla se esiste un percorso nel sistema. PATH può essere una DIRECTORY o un FILE. Funzionerà bene su entrambi i casi. Prova con un esempio
Pradip Das,

Quindi, questa risposta funziona. Grande. Se il percorso non è quello di un file. È questa la domanda? No.
Debosmit Ray

Dipende. Se l'obiettivo di determinare l'esistenza di un "file" è scoprire se il percorso esiste già (e quindi non è un percorso in cui è possibile archiviare nuovi dati senza eliminare altre informazioni), allora existsva bene. Se l'obiettivo è determinare se è sicuro aprire un file presumibilmente esistente, le critiche sono giustificate ed esistono non abbastanza precise. Purtroppo, l'OP non specifica quale sia l'obiettivo desiderato (e probabilmente non lo farà più).
starturtle

12

Come posso verificare se esiste un file, senza usare l'istruzione try?

Nel 2016, questo è ancora probabilmente il modo più semplice per verificare se esiste un file e se si tratta di un file:

import os
os.path.isfile('./file.txt')    # Returns True if exists, else False

isfileè in realtà solo un metodo di supporto che utilizza internamente os.state stat.S_ISREG(mode)sotto. Questo os.statè un metodo di livello inferiore che ti fornirà informazioni dettagliate su file, directory, socket, buffer e altro. Maggiori informazioni su os.stat qui

Nota: tuttavia, questo approccio non bloccherà il file in alcun modo e pertanto il codice può diventare vulnerabile ai bug " TOCTTOU " " time of check to time of use " .

Pertanto, sollevare eccezioni è considerato un approccio accettabile e Pythonic per il controllo del flusso nel programma. E si dovrebbe considerare la gestione dei file mancanti con IOErrors, piuttosto che le ifdichiarazioni ( solo un consiglio ).


9
import os.path

def isReadableFile(file_path, file_name):
    full_path = file_path + "/" + file_name
    try:
        if not os.path.exists(file_path):
            print "File path is invalid."
            return False
        elif not os.path.isfile(full_path):
            print "File does not exist."
            return False
        elif not os.access(full_path, os.R_OK):
            print "File cannot be read."
            return False
        else:
            print "File can be read."
            return True
    except IOError as ex:
        print "I/O error({0}): {1}".format(ex.errno, ex.strerror)
    except Error as ex:
        print "Error({0}): {1}".format(ex.errno, ex.strerror)
    return False
#------------------------------------------------------

path = "/usr/khaled/documents/puzzles"
fileName = "puzzle_1.txt"

isReadableFile(path, fileName)

@ j6m8 sì, isReadableFile(path,fileName)verrà restituito Truese il file è raggiungibile e leggibile dal processo \ programma \ thread
Khaled.K
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.