HOWTO · Csharp
Controlla se un file esiste in C#
Il metodo File.Exists() può essere utilizzato per verificare se un file esiste in un percorso specifico in C#.
In questa pagina
Prima che il programma legga, scriva o elimini un file, spesso è utile sapere se il file è davvero presente. C# offre questo controllo tramite File.Exists, un metodo dello spazio dei nomi System.IO che verifica un percorso e restituisce una risposta booleana. Questa guida mostra come chiamarlo, come i percorsi relativi e assoluti determinano ciò che viene controllato, che cosa indica davvero un risultato false e come agire sulla risposta senza fidarsi troppo.
Verifica se un file esiste con File.Exists
File.Exists è un metodo statico, quindi lo chiami sulla classe File stessa anziché su un’istanza. Gli passi un percorso come stringa e restituisce true quando il sistema operativo può confermare un file normale in quel percorso e false quando non può.
Esegui questo esempio:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
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);
}
}
Risultato:
Does the file exist? True
Il programma crea un piccolo file nella directory temporanea del sistema, lo verifica con File.Exists e stampa la risposta, che è True perché il file è appena stato creato; l’etichetta Does the file exist? resta in inglese perché fa parte del codice di esempio. Fai puntare path alla posizione che devi controllare; la chiamata rimane la stessa e il risultato è sempre un semplice bool, pronto per un’istruzione if o per una variabile da conservare.
Scegli il percorso da controllare
La stringa che passi determina quale posizione viene esaminata, quindi sceglila con attenzione.
Un percorso assoluto indica completamente il file — C:\Data\report.txt in Windows o /var/data/report.txt in Linux. Fa riferimento allo stesso punto indipendentemente da dove viene avviato il programma, quindi preferiscilo quando la posizione è fissa o proviene dalla configurazione o dall’input dell’utente.
Un percorso relativo come report.txt o logs/report.txt viene risolto rispetto alla directory di lavoro del processo, cioè al valore di Environment.CurrentDirectory. Di solito è la cartella in cui il processo è stato avviato — non necessariamente quella che contiene l’eseguibile — e altro codice può modificarla, quindi un percorso relativo può puntare silenziosamente a una posizione diversa da quella prevista.
Esegui questo esempio per vedere lo stesso nome relativo risolversi in due posizioni diverse:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
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);
}
}
Risultato:
False
True
Il primo controllo cerca il file nella directory di lavoro originale e non trova nulla. Dopo che Directory.SetCurrentDirectory sposta il processo nella cartella che contiene il file, lo stesso nome relativo viene risolto in quel punto e il controllo restituisce True.
Quando scrivi percorsi Windows nel codice sorgente C#, la barra rovesciata richiede attenzione solo per la sintassi delle stringhe, non perché Windows richieda separatori raddoppiati. In una stringa normale, \ inizia una sequenza di escape, quindi scrivi "C:\\Data\\report.txt"; in una stringa verbatim preceduta da @, usa barre rovesciate singole: @"C:\Data\report.txt". .NET accetta anche le barre normali ("C:/Data/report.txt") su Windows, e in Linux e macOS / è il separatore standard, quindi Path.Combine è il modo più portabile per costruire i percorsi.
Interpreta il risultato e le sue limitazioni
File.Exists risponde a una domanda precisa: il sistema operativo può confermare adesso la presenza di un file in questo percorso? Interpreta false come «non può confermare», non specificamente come «il file è assente». Il metodo restituisce false anche quando il percorso è null o non valido, quando indica una directory anziché un file (usa Directory.Exists per le cartelle) e quando il controllo stesso incontra problemi, ad esempio la mancanza delle autorizzazioni per attraversare le cartelle.
Questi problemi confluiscono nel risultato false anziché essere sollevati come eccezioni, quindi un try/catch intorno a File.Exists quasi non osserverà mai nulla. Se il programma deve sapere perché un percorso ha fallito — per registrarlo, avvisare l’utente o decidere se riprovare — verifica tu stesso la condizione specifica oppure tenta direttamente l’operazione reale sul file e leggi l’errore che restituisce.
La chiamata è sincrona e accede al file system. In genere è veloce, ma può richiedere un tempo percettibile su una condivisione di rete o un disco lento, quindi evita di chiamarla in un ciclo stretto quando basta un singolo risultato memorizzato.
Usa il risultato in modo sicuro
Considera la risposta come un’istantanea, non una garanzia. Tra la chiamata a File.Exists e il momento in cui apri il file, un altro processo — o un altro thread del tuo stesso programma — può eliminarlo, spostarlo o sostituirlo, e anche if (File.Exists(path)) File.ReadAllText(path) può ancora fallire.
L’abitudine più robusta è agire sul file e gestire l’esito dell’operazione stessa:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
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);
}
}
Risultato:
hello from disk
Qui File.Exists salta il lavoro in modo pulito quando non c’è nulla, mentre il try/catch intorno a File.ReadAllText copre ciò che il controllo non può gestire: un file scomparso (segnalato come FileNotFoundException, un tipo di IOException), un file bloccato da un altro processo o un accesso negato; i messaggi stampati nell’esempio restano in inglese perché fanno parte del codice. Quando l’unico obiettivo è leggere il file, puoi eliminare il controllo e lasciare che il catch gestisca l’assenza, rimuovendo del tutto la race condition. Mantieni File.Exists per le decisioni in cui la risposta booleana è sufficiente da sola: mostrare un messaggio, scegliere tra creare e aprire un file oppure saltare un passaggio di pulizia.