Menu

Verificare se un file esiste in Python: os.path, pathlib e try/except

Tre modi per verificare se un file esiste in Python: os.path.exists e isfile, Path.exists e is_file di pathlib, e aprire il file dentro try/except FileNotFoundError.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

La risposta breve

Per verificare se un file esiste, usa os.path.isfile() della libreria standard. Restituisce True quando il percorso indica un file regolare esistente e False altrimenti. Non solleva mai un errore per un percorso mancante.

I percorsi sono relativi alla cartella in cui gira il programma (la directory di lavoro corrente), a meno che tu non passi un percorso assoluto come /home/ada/notes.txt o C:\Users\Ada\notes.txt.

Il resto della pagina mostra gli altri modi per porre la domanda, in cosa differiscono e il caso in cui non dovresti porla affatto.

os.path.exists vs isfile vs isdir

Il modulo os.path ha tre controlli collegati, che rispondono a domande leggermente diverse:

FunzioneRestituisce True quando il percorso è
os.path.exists(p)qualsiasi cosa esista: un file, una cartella o un link simbolico funzionante
os.path.isfile(p)un file regolare esistente
os.path.isdir(p)una cartella esistente

La differenza si vede appena c'è di mezzo una cartella:

Output:

reports True False True
reports/summary.txt True True False
reports/old.txt False False False

os.path.exists("reports") è True anche se reports è una cartella. Se il tuo codice sta per leggere il percorso come file, exists è il controllo sbagliato: una cartella lo supererebbe, e poi open("reports") fallirebbe (con IsADirectoryError su Linux e macOS, PermissionError su Windows). Scegli isfile quando intendi un file e isdir quando intendi una cartella.

Altri due dettagli su queste tre funzioni di os.path:

  • I link simbolici vengono seguiti. Un link che punta a un file reale conta come file; un link rotto (la destinazione non c'è più) restituisce False da tutte e tre.
  • Se Python non ha il permesso di guardare dentro una cartella, il controllo restituisce False invece di sollevare PermissionError. False significa "non trovato o non raggiungibile", non strettamente "non esiste".

Verificare con pathlib

pathlib è l'API a oggetti per i percorsi della libreria standard, e la usa la maggior parte del codice nuovo. Un oggetto Path ha gli stessi tre controlli come metodi:

Path.exists(), Path.is_file() e Path.is_dir() si comportano come os.path.exists, isfile e isdir. L'operatore / unisce le parti del percorso con il separatore giusto per il sistema operativo, quindi folder / "summary.txt" funziona allo stesso modo su Windows, macOS e Linux. Vedi la gestione dei file per leggere e scrivere tramite oggetti Path.

Quale usare? Se il resto del tuo codice passa già oggetti Path, resta su pathlib. Se lavori con stringhe semplici e funzioni di os, os.path.isfile è altrettanto corretto. Danno le stesse risposte.

Perché verificare prima può essere la mossa sbagliata

Il motivo più comune per verificare se un file esiste è aprirlo subito dopo:

import os

if os.path.isfile("config.txt"):
    with open("config.txt") as f:      # il file potrebbe non esserci più
        settings = f.read()
else:
    settings = ""

C'è un buco. Tra la chiamata a isfile() e quella a open(), un altro programma, un altro thread o l'utente possono cancellare o rinominare il file. Il controllo ha detto True, l'apertura fallisce comunque e il tuo programma si blocca con FileNotFoundError. Questo buco si chiama race condition, o "time of check to time of use". È raro sul tuo portatile e molto meno raro su un server affollato dove più processi condividono una cartella.

La soluzione è saltare il controllo separato e lasciare che sia open() a fare il controllo. Python solleva FileNotFoundError quando il file manca, e tu lo gestisci in except:

Output:

theme=dark
(no settings file, using defaults)

Ora c'è un'operazione sola invece di due, quindi non c'è nessuna corsa possibile. Nella comunità Python questo stile ha un nome: EAFP, "easier to ask forgiveness than permission" (è più facile chiedere perdono che permesso). Lo stile opposto, controllare prima, è LBYL, "look before you leap" (guarda prima di saltare). Per i file Python preferisce EAFP, perché solo il sistema operativo conosce la risposta nel momento in cui apri il file.

FileNotFoundError non è l'unica cosa che può andare storta. Un percorso che è una cartella solleva IsADirectoryError (PermissionError su Windows), e un file che non puoi leggere solleva PermissionError. Sono tutte e tre sottoclassi di OSError, quindi except OSError: cattura in un colpo solo ogni caso di "non sono riuscito ad aprirlo". La pagina sulle eccezioni spiega come scegliere tra catturare un errore specifico e catturarne un'intera famiglia.

Quando un semplice controllo va bene

Verificare prima non è sbagliato in ogni caso. È lo strumento giusto quando ti serve solo la risposta e non stai per agire sul file alla riga successiva:

  • scegliere quale messaggio mostrare ("Found 3 saved games")
  • validare un percorso digitato dall'utente prima di avviare un lavoro lungo
  • saltare un lavoro già fatto, dove una risposta non aggiornata costa al massimo una ripetizione

La regola pratica: se stai per aprire, leggere, scrivere o cancellare il file, fallo dentro try. Se vuoi solo saperlo, isfile() o Path.is_file() vanno benissimo.

Creare un file solo se non esiste

Capita anche la domanda opposta: "scrivi questo file, ma non sovrascriverne mai uno esistente". La versione più ovvia ha la stessa race condition di prima:

if not os.path.exists("report.txt"):
    with open("report.txt", "w") as f:   # un altro processo può crearlo prima
        f.write("new report\n")

La modalità "x" (creazione esclusiva) fa entrambi i passaggi in uno. Crea il file, oppure solleva FileExistsError se il nome è già preso:

Output:

attempt 1: created report.txt
attempt 2: report.txt already exists, left it alone

Per le cartelle, os.makedirs(path, exist_ok=True) e Path(path).mkdir(parents=True, exist_ok=True) creano la cartella e tutte quelle superiori mancanti, e non fanno nulla se esiste già. Non serve chiamare prima isdir().

Errori comuni

  • Usare exists() quando intendi un file. Una cartella con lo stesso nome supera il controllo. Usa isfile() o Path.is_file().
  • Dimenticare da dove partono i percorsi relativi. "data.txt" viene cercato nella directory di lavoro corrente, cioè dove hai avviato il programma, non per forza la cartella che contiene lo script. Per trovare un file accanto allo script, costruisci il percorso partendo da Path(__file__).parent.
  • Verificare e poi aprire. Il file può cambiare nel frattempo. Apri dentro try e gestisci FileNotFoundError.
  • Catturare qualsiasi eccezione. except Exception: attorno a open() nasconde anche errori di battitura e bug nel codice che legge il file. Cattura FileNotFoundError o OSError.

Domande frequenti

Come verifico se un file esiste in Python?

Importa os e chiama os.path.isfile("data.txt"), che restituisce True solo per un file regolare esistente. Con pathlib è Path("data.txt").is_file(). Usa os.path.exists() o Path.exists() quando anche una cartella con quel nome deve contare.

Qual è la differenza tra os.path.exists e os.path.isfile?

os.path.exists(p) è True per qualsiasi cosa si trovi in quel percorso: un file, una cartella o un link simbolico che punta a qualcosa di reale. os.path.isfile(p) è True solo per un file regolare, quindi restituisce False per una cartella. os.path.isdir(p) è l'equivalente per le cartelle.

Devo verificare se un file esiste prima di aprirlo?

Di solito no. Il file può essere cancellato o creato tra il controllo e la chiamata a open(), quindi il controllo non garantisce nulla. Apri il file direttamente dentro try e gestisci FileNotFoundError in except. Un controllo separato ha senso quando ti serve solo la risposta, per esempio per decidere quale messaggio mostrare.

Come creo un file solo se non esiste?

Aprilo in modalità "x": open("report.txt", "x"). Python crea il file, oppure solleva FileExistsError se lì c'è già qualcosa. Il controllo e la creazione avvengono in un solo passaggio, quindi nessun altro programma può inserirsi in mezzo.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA