HOWTO · Csharp

Comprobar si existe un archivo en C#

El método File.Exists() permite comprobar si un archivo existe en una ruta específica en C#.

En esta página

Antes de que tu programa lea, escriba o elimine un archivo, a menudo conviene saber si el archivo realmente está ahí. C# proporciona esa comprobación mediante File.Exists, un método del espacio de nombres System.IO que prueba una ruta y devuelve una respuesta booleana. Esta guía muestra cómo llamarlo, cómo las rutas relativas y absolutas deciden qué se comprueba, qué te dice realmente un resultado false y cómo actuar según la respuesta sin confiar en ella más de la cuenta.

Comprobar si un archivo existe con File.Exists

File.Exists es un método estático, por lo que se llama sobre la propia clase File y no sobre una instancia. Le pasas una ruta como cadena y devuelve true cuando el sistema operativo puede confirmar un archivo normal en esa ruta, y false cuando no puede.

Ejecuta este ejemplo (el código y el texto que imprime se mantienen en inglés, igual que en el original):

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = Path.Combine(Path.GetTempPath(), "delftstack-demo.txt");
        File.WriteAllText(path, "demo content");
        bool fileExists = File.Exists(path);
        Console.WriteLine($"Does the file exist? {fileExists}");
        File.Delete(path);
    }
}

Salida:

Does the file exist? True

El programa crea un pequeño archivo en el directorio temporal del sistema, pregunta a File.Exists por él e imprime la respuesta, que es True porque el archivo acaba de crearse; la etiqueta visible («Does the file exist?») permanece en inglés, como en el código original. Apunta path a la ubicación que necesites comprobar; la llamada sigue siendo la misma y el resultado es siempre un simple bool, listo para una sentencia if o para una variable que conserves.

Elegir la ruta que se va a comprobar

La cadena que pasas decide qué ubicación se examina, así que elígela deliberadamente.

Una ruta absoluta nombra el archivo por completo: C:\Data\report.txt en Windows o /var/data/report.txt en Linux. Se refiere al mismo lugar sin importar desde dónde se ejecute tu programa, por lo que es preferible cuando la ubicación es fija o proviene de la configuración o de la entrada del usuario.

Una ruta relativa como report.txt o logs/report.txt se resuelve respecto al directorio de trabajo del proceso, el valor de Environment.CurrentDirectory. Normalmente es la carpeta en la que se inició el proceso —no necesariamente la carpeta que contiene tu ejecutable— y otro código puede cambiarla, por lo que una ruta relativa puede apuntar silenciosamente a un lugar distinto del que esperas.

Ejecuta este ejemplo para ver cómo el mismo nombre relativo se resuelve en dos lugares distintos (el código se mantiene en inglés):

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string dir = Path.Combine(Path.GetTempPath(), "delftstack-cwd-demo");
        Directory.CreateDirectory(dir);
        File.WriteAllText(Path.Combine(dir, "delftstack-report-7f3a1c.txt"), "demo");

        Console.WriteLine(File.Exists("delftstack-report-7f3a1c.txt"));

        Directory.SetCurrentDirectory(dir);
        Console.WriteLine(File.Exists("delftstack-report-7f3a1c.txt"));

        Directory.SetCurrentDirectory(Path.GetTempPath());
        File.Delete(Path.Combine(dir, "delftstack-report-7f3a1c.txt"));
        Directory.Delete(dir);
    }
}

Salida:

False
True

La primera comprobación busca el archivo en el directorio de trabajo original y no encuentra nada. Después de que Directory.SetCurrentDirectory traslade el proceso a la carpeta que contiene el archivo, el mismo nombre relativo se resuelve hasta él y la comprobación devuelve True.

Cuando escribes rutas de Windows en código fuente de C#, la barra invertida solo requiere atención por la sintaxis de las cadenas, no porque Windows exija separadores duplicados. En una cadena normal, \ inicia una secuencia de escape, así que escribe "C:\\Data\\report.txt"; en una cadena textual con el prefijo @, escribe barras invertidas simples: @"C:\Data\report.txt". .NET también acepta barras diagonales ("C:/Data/report.txt") en Windows, y en Linux y macOS / es el separador normal, por lo que Path.Combine es la forma más portable de construir rutas.

Interpretar el resultado y sus limitaciones

File.Exists responde a una única pregunta concreta: ¿puede el sistema operativo confirmar un archivo en esta ruta ahora mismo? Lee false como «no se puede confirmar», no específicamente como «el archivo no existe». El método también devuelve false cuando la ruta es null o está mal formada, cuando la ruta nombra un directorio en lugar de un archivo (usa Directory.Exists para las carpetas) y cuando la propia comprobación encuentra problemas, como la falta de permiso para recorrer las carpetas.

Esos problemas se pliegan en el resultado false en lugar de producirse como excepciones, por lo que un try/catch alrededor de File.Exists casi nunca observará nada. Si tu programa necesita saber por qué falló una ruta —para registrarlo, avisar al usuario o decidir si reintentar—, comprueba tú mismo la condición concreta o simplemente intenta la operación de archivo real y lee el error que informa.

La llamada es síncrona y accede al sistema de archivos. Normalmente es rápida, pero puede tardar un tiempo apreciable en un recurso compartido de red o en un disco lento, así que evita llamarla en un bucle cerrado cuando baste con un único resultado almacenado.

Usar el resultado de forma segura

Trata la respuesta como una instantánea, no como una garantía. Entre tu llamada a File.Exists y el momento en que abres el archivo, otro proceso —u otro hilo de tu propio programa— puede eliminarlo, moverlo o reemplazarlo, e incluso if (File.Exists(path)) File.ReadAllText(path) puede seguir fallando.

El hábito robusto es actuar sobre el archivo y manejar el resultado de la propia operación (el código y los mensajes que imprime se mantienen en inglés):

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = Path.Combine(Path.GetTempPath(), "delftstack-read-demo.txt");
        File.WriteAllText(path, "hello from disk");

        if (File.Exists(path))
        {
            try
            {
                Console.WriteLine(File.ReadAllText(path));
            }
            catch (IOException)
            {
                Console.WriteLine("The file could not be read.");
            }
            catch (UnauthorizedAccessException)
            {
                Console.WriteLine("Access to the file was denied.");
            }
        }

        File.Delete(path);
    }
}

Salida:

hello from disk

Aquí File.Exists omite el trabajo limpiamente cuando no hay nada, mientras que el try/catch alrededor de File.ReadAllText cubre lo que la comprobación no puede: un archivo que ha desaparecido (que surge como FileNotFoundException, un tipo de IOException), un archivo bloqueado por otro proceso o un acceso denegado. La salida visible («hello from disk» y los mensajes de error) permanece en inglés, como en el código original. Cuando tu único objetivo es leer el archivo, puedes prescindir de la comprobación y dejar que el catch gestione la ausencia, lo que elimina la carrera por completo. Reserva File.Exists para las decisiones en las que la respuesta booleana basta por sí sola: mostrar un mensaje, elegir entre crear y abrir un archivo, u omitir un paso de limpieza.