Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Oltre alle eccezioni che possono essere generate in qualsiasi chiamata al metodo (ad esempio OutOfMemoryException quando un sistema è stressato o a causa di un NullReferenceException errore del programmatore), i metodi del file system .NET possono generare le eccezioni seguenti:
- System.IO.IOException, la classe base di tutti i System.IO tipi di eccezione. Viene generata per errori i cui codici di restituzione dal sistema operativo non corrispondono direttamente ad altri tipi di eccezione.
- System.IO.FileNotFoundException.
- System.IO.DirectoryNotFoundException.
- DriveNotFoundException.
- System.IO.PathTooLongException.
- System.OperationCanceledException.
- System.UnauthorizedAccessException.
- System.ArgumentException, che viene lanciata per caratteri di percorso non validi in .NET Framework e in .NET Core 2.0 e versioni precedenti.
- System.NotSupportedException, lanciata per i due punti non validi in .NET Framework.
- System.Security.SecurityException, generata per applicazioni eseguite con fiducia limitata che non hanno le autorizzazioni necessarie, solo nel .NET Framework. L'attendibilità completa è l'impostazione predefinita in .NET Framework.
Mappatura dei codici di errore alle eccezioni
Poiché il file system è una risorsa del sistema operativo, i metodi di I/O in .NET Core e .NET Framework eseguono il wrapping delle chiamate al sistema operativo sottostante. Quando si verifica un errore di I/O nel codice eseguito dal sistema operativo, il sistema operativo restituisce le informazioni sull'errore al metodo di I/O .NET. Il metodo converte quindi le informazioni sull'errore, in genere sotto forma di codice di errore, in un tipo di eccezione .NET. Nella maggior parte dei casi, esegue questa operazione convertendo direttamente il codice di errore nel tipo di eccezione corrispondente; non esegue alcun mapping speciale dell'errore in base al contesto della chiamata al metodo.
Nel sistema operativo Windows, ad esempio, una chiamata al metodo che restituisce un codice di errore di ERROR_FILE_NOT_FOUND (o 0x02) esegue il mapping a un FileNotFoundExceptionoggetto e un codice di errore di ERROR_PATH_NOT_FOUND (o 0x03) esegue il mapping a un oggetto DirectoryNotFoundException.
Tuttavia, le condizioni precise in cui il sistema operativo restituisce codici di errore specifici spesso non documentati o non documentati correttamente. Di conseguenza, possono verificarsi eccezioni impreviste. Ad esempio, poiché si usa una directory anziché un file, si prevede che fornire un percorso di directory non valido al DirectoryInfo costruttore generi un'eccezione DirectoryNotFoundException. Tuttavia, può anche generare un'eccezione FileNotFoundException.
Gestione delle eccezioni nelle operazioni di I/O
A causa di questa dipendenza dal sistema operativo, condizioni di eccezione identiche (come l'errore di directory non trovata nel nostro esempio) possono causare un metodo di I/O che solleva una delle molteplici eccezioni di I/O della classe completa. Ciò significa che, quando si chiamano le API di I/O, il codice deve essere preparato per gestire la maggior parte o tutte queste eccezioni, come illustrato nella tabella seguente:
| Tipo di eccezione | .NET Core/.NET 5+ | .NET Framework |
|---|---|---|
| IOException | Sì | Sì |
| FileNotFoundException | Sì | Sì |
| DirectoryNotFoundException | Sì | Sì |
| DriveNotFoundException | Sì | Sì |
| PathTooLongException | Sì | Sì |
| OperationCanceledException | Sì | Sì |
| UnauthorizedAccessException | Sì | Sì |
| ArgumentException | .NET Core 2.0 e versioni precedenti | Sì |
| NotSupportedException | NO | Sì |
| SecurityException | NO | Solo attendibilità limitata |
Gestione di IOException
Come classe base per le eccezioni nello spazio dei nomi System.IO, IOException viene lanciata anche per qualsiasi codice di errore che non è associato a un tipo di eccezione predefinito. Ciò significa che può essere generata da qualsiasi operazione di I/O.
Importante
Poiché IOException è la classe base degli altri tipi di eccezione nello System.IO spazio dei nomi, è necessario gestire in un catch blocco dopo aver gestito le altre eccezioni correlate all'I/O.
Inoltre, a partire da .NET Core 2.1, i controlli di convalida per la correttezza del percorso (ad esempio, per assicurarsi che i caratteri non validi non siano presenti in un percorso) siano stati rimossi e il runtime genera un'eccezione mappata da un codice di errore del sistema operativo anziché dal proprio codice di convalida. L'eccezione più probabile che venga sollevata in questo caso è un IOException, sebbene possa essere sollevato qualsiasi altro tipo di eccezione.
Si noti che, nel codice di gestione delle eccezioni, si dovrebbe gestire sempre IOException per ultimo. In caso contrario, poiché è la classe base di tutte le altre eccezioni di I/O, i blocchi catch delle classi derivate non verranno valutati.
Nel caso di un IOException, puoi ottenere ulteriori informazioni sull'errore dalla proprietà IOException.HResult. Per convertire il valore HResult in un codice di errore Win32, rimuovere i 16 bit superiori del valore a 32 bit. Nella tabella seguente sono elencati i codici di errore di cui è possibile eseguire il wrapping in un oggetto IOException.
| HResult | Costante | Descrizione |
|---|---|---|
| ERRORE_VIOLAZIONE_CONDIVISIONE | 32 | Il nome del file è mancante oppure il file o la directory è in uso. |
| ERRORE_FILE_ESISTE | 80 | Il file esiste già. |
| ERRORE_PARAMETRO_NON_VALIDO | 87 | Un argomento fornito al metodo non è valido. |
| ERRORE_GIÀ_ESISTENTE | 183 | Il file o la directory esiste già. |
È possibile gestirli usando una When clausola in un'istruzione catch, come illustrato nell'esempio seguente.
using System;
using System.IO;
using System.Text;
class Program
{
static void Main()
{
var sw = OpenStream(@".\textfile.txt");
if (sw is null)
return;
sw.WriteLine("This is the first line.");
sw.WriteLine("This is the second line.");
sw.Close();
}
static StreamWriter? OpenStream(string path)
{
if (path is null)
{
Console.WriteLine("You did not supply a file path.");
return null;
}
try
{
var fs = new FileStream(path, FileMode.CreateNew);
return new StreamWriter(fs);
}
catch (FileNotFoundException)
{
Console.WriteLine("The file or directory cannot be found.");
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("The file or directory cannot be found.");
}
catch (DriveNotFoundException)
{
Console.WriteLine("The drive specified in 'path' is invalid.");
}
catch (PathTooLongException)
{
Console.WriteLine("'path' exceeds the maximum supported path length.");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("You do not have permission to create this file.");
}
catch (IOException e) when ((e.HResult & 0x0000FFFF) == 32)
{
Console.WriteLine("There is a sharing violation.");
}
catch (IOException e) when ((e.HResult & 0x0000FFFF) == 80)
{
Console.WriteLine("The file already exists.");
}
catch (IOException e)
{
Console.WriteLine($"An exception occurred:\nError code: " +
$"{e.HResult & 0x0000FFFF}\nMessage: {e.Message}");
}
return null;
}
}
Imports System.IO
Module Program
Sub Main(args As String())
Dim sw = OpenStream(".\textfile.txt")
If sw Is Nothing Then Return
sw.WriteLine("This is the first line.")
sw.WriteLine("This is the second line.")
sw.Close()
End Sub
Function OpenStream(path As String) As StreamWriter
If path Is Nothing Then
Console.WriteLine("You did not supply a file path.")
Return Nothing
End If
Try
Dim fs As New FileStream(path, FileMode.CreateNew)
Return New StreamWriter(fs)
Catch e As FileNotFoundException
Console.WriteLine("The file or directory cannot be found.")
Catch e As DirectoryNotFoundException
Console.WriteLine("The file or directory cannot be found.")
Catch e As DriveNotFoundException
Console.WriteLine("The drive specified in 'path' is invalid.")
Catch e As PathTooLongException
Console.WriteLine("'path' exceeds the maximum supported path length.")
Catch e As UnauthorizedAccessException
Console.WriteLine("You do not have permission to create this file.")
Catch e As IOException When (e.HResult And &h0000FFFF) = 32
Console.WriteLine("There is a sharing violation.")
Catch e As IOException When (e.HResult And &h0000FFFF) = 80
Console.WriteLine("The file already exists.")
Catch e As IOException
Console.WriteLine($"An exception occurred:{vbCrLf}Error code: " +
$"{e.HResult And &h0000FFFF}{vbCrLf}Message: {e.Message}")
End Try
Return Nothing
End Function
End Module