La respuesta corta
Para comprobar si un archivo existe, usa os.path.isfile() de la biblioteca estándar. Devuelve True cuando la ruta nombra un archivo regular que existe y False en caso contrario. Nunca lanza un error por una ruta que no existe.
Las rutas son relativas a la carpeta desde la que se ejecuta el programa (el directorio de trabajo actual), salvo que pases una ruta absoluta como /home/ada/notes.txt o C:\Users\Ada\notes.txt.
El resto de esta página cubre las otras formas de hacer la pregunta, en qué se diferencian y el caso en que no deberías hacerla.
os.path.exists vs isfile vs isdir
El módulo os.path tiene tres comprobaciones relacionadas, y responden a preguntas ligeramente distintas:
| Función | Devuelve True cuando la ruta es |
|---|---|
os.path.exists(p) | cualquier cosa que exista: un archivo, un directorio o un enlace simbólico válido |
os.path.isfile(p) | un archivo regular que existe |
os.path.isdir(p) | un directorio que existe |
La diferencia aparece en cuanto hay un directorio de por medio:
Salida:
reports True False True
reports/summary.txt True True False
reports/old.txt False False False
os.path.exists("reports") es True aunque reports sea una carpeta. Si tu código va a leer la ruta como un archivo, exists es la comprobación equivocada: un directorio la pasaría, y luego open("reports") fallaría (con IsADirectoryError en Linux y macOS, PermissionError en Windows). Elige isfile cuando te refieras a un archivo e isdir cuando te refieras a una carpeta.
Dos detalles más sobre estas tres funciones de os.path:
- Los enlaces simbólicos se siguen. Un enlace que apunta a un archivo real cuenta como archivo; un enlace roto (su destino ya no existe) devuelve
Falseen las tres. - Si Python no tiene permiso para mirar dentro de una carpeta, la comprobación devuelve
Falseen lugar de lanzarPermissionError.Falsesignifica "no encontrado o no accesible", no estrictamente "no existe".
Comprobarlo con pathlib
pathlib es la API orientada a objetos para rutas de la biblioteca estándar, y la mayoría del código nuevo la usa. Un objeto Path tiene las mismas tres comprobaciones como métodos:
Path.exists(), Path.is_file() y Path.is_dir() se comportan como os.path.exists, isfile e isdir. El operador / une partes de una ruta con el separador correcto para el sistema operativo, así que folder / "summary.txt" funciona igual en Windows, macOS y Linux. Consulta manejo de archivos para leer y escribir a través de objetos Path.
¿Cuál deberías usar? Si el resto de tu código ya pasa objetos Path de un lado a otro, quédate con pathlib. Si trabajas con strings normales y funciones de os, os.path.isfile es igual de correcto. Dan las mismas respuestas.
Por qué comprobar primero puede ser un error
La razón más común para comprobar si un archivo existe es abrirlo después:
import os
if os.path.isfile("config.txt"):
with open("config.txt") as f: # puede que el archivo ya no esté
settings = f.read()
else:
settings = ""
Esto tiene un hueco. Entre la llamada a isfile() y la llamada a open(), otro programa, otro hilo o el propio usuario pueden borrar o renombrar el archivo. La comprobación dijo True, la apertura falla igualmente y tu programa se detiene con FileNotFoundError de todos modos. Ese hueco se llama condición de carrera, o "time of check to time of use" (del momento de la comprobación al momento del uso). Es raro en tu propio portátil y bastante menos raro en un servidor con mucha carga donde varios procesos comparten una carpeta.
La solución es saltarse la comprobación aparte y dejar que open() sea la comprobación. Python lanza FileNotFoundError cuando falta el archivo, y tú lo manejas en except:
Salida:
theme=dark
(no settings file, using defaults)
Ahora hay una sola operación en lugar de dos, así que no hay carrera posible. Este estilo tiene nombre en la comunidad de Python: EAFP, "easier to ask forgiveness than permission" (es más fácil pedir perdón que permiso). El estilo contrario, comprobar primero, es LBYL, "look before you leap" (mira antes de saltar). Python se inclina por EAFP al trabajar con archivos porque el sistema operativo es lo único que conoce la respuesta en el momento en que abres el archivo.
FileNotFoundError no es lo único que puede salir mal. Una ruta que es un directorio lanza IsADirectoryError (PermissionError en Windows), y un archivo que no puedes leer lanza PermissionError. Las tres son subclases de OSError, así que except OSError: captura de una vez todos los casos de "no se pudo abrir". La página de excepciones explica cómo elegir entre capturar un error concreto y capturar una familia.
Cuándo una comprobación simple está bien
Comprobar primero no está mal en todos los casos. Es la herramienta adecuada cuando solo necesitas la respuesta y no vas a actuar sobre el archivo en la línea siguiente:
- elegir qué mensaje mostrar ("Found 3 saved games")
- validar una ruta que escribió el usuario antes de empezar un trabajo largo
- saltarse trabajo que ya se hizo, donde una respuesta desactualizada solo cuesta repetirlo
La regla general: si vas a abrir, leer, escribir o borrar el archivo, hazlo dentro de try. Si solo quieres saberlo, isfile() o Path.is_file() está bien.
Crear un archivo solo si no existe
También surge la pregunta inversa: "escribe este archivo, pero nunca sobrescribas uno que ya exista". La versión obvia tiene la misma carrera que antes:
if not os.path.exists("report.txt"):
with open("report.txt", "w") as f: # otro proceso puede crearlo primero
f.write("new report\n")
El modo "x" (creación exclusiva) hace ambos pasos en uno. Crea el archivo, o lanza FileExistsError si el nombre ya está ocupado:
Salida:
attempt 1: created report.txt
attempt 2: report.txt already exists, left it alone
Para carpetas, os.makedirs(path, exist_ok=True) y Path(path).mkdir(parents=True, exist_ok=True) crean el directorio y cualquier directorio padre que falte, y no hacen nada si ya existe. No hace falta llamar antes a isdir().
Errores comunes
- Usar
exists()cuando te refieres a un archivo. Un directorio con el mismo nombre pasa la comprobación. Usaisfile()oPath.is_file(). - Olvidar desde dónde empiezan las rutas relativas.
"data.txt"se busca en el directorio de trabajo actual, que es desde donde lanzaste el programa, no necesariamente la carpeta que contiene el script. Para encontrar un archivo junto al script, construye la ruta a partir dePath(__file__).parent. - Comprobar y después abrir. El archivo puede cambiar entre medias. Ábrelo dentro de
tryy manejaFileNotFoundError. - Capturar cualquier excepción.
except Exception:alrededor deopen()también oculta erratas y bugs en el código que lee el archivo. CapturaFileNotFoundErroruOSError.
Preguntas frecuentes
¿Cómo compruebo si un archivo existe en Python?
Importa os y llama a os.path.isfile("data.txt"), que devuelve True solo para un archivo regular que existe. Con pathlib es Path("data.txt").is_file(). Usa os.path.exists() o Path.exists() cuando también deba contar un directorio con ese nombre.
¿Cuál es la diferencia entre os.path.exists y os.path.isfile?
os.path.exists(p) es True para cualquier cosa en esa ruta: un archivo, un directorio o un enlace simbólico que apunta a algo real. os.path.isfile(p) es True solo para un archivo regular, así que devuelve False para un directorio. os.path.isdir(p) es su equivalente para directorios.
¿Debo comprobar si un archivo existe antes de abrirlo?
Normalmente no. El archivo puede borrarse o crearse entre la comprobación y la llamada a open(), así que la comprobación no garantiza nada. Abre el archivo directamente dentro de try y maneja FileNotFoundError en except. Una comprobación aparte es lo correcto cuando solo necesitas la respuesta, por ejemplo para decidir qué mensaje mostrar.
¿Cómo creo un archivo solo si no existe?
Ábrelo con el modo "x": open("report.txt", "x"). Python crea el archivo, o lanza FileExistsError si ya hay algo con ese nombre. La comprobación y la creación ocurren en un solo paso, así que ningún otro programa puede colarse entre ambas.