Delen via


I/O-fouten verwerken in .NET

Naast de uitzonderingen die kunnen worden gegenereerd in een methodeaanroep (zoals wanneer OutOfMemoryException een systeem wordt gestrest of als gevolg NullReferenceException van een programmeurfout), kunnen .NET-bestandssysteemmethoden de volgende uitzonderingen veroorzaken:

Foutcodes toewijzen aan uitzonderingen

Omdat het bestandssysteem een besturingssysteemresource is, verpakken I/O-methoden in zowel .NET Core als .NET Framework aanroepen naar het onderliggende besturingssysteem. Wanneer een I/O-fout optreedt in code die door het besturingssysteem wordt uitgevoerd, retourneert het besturingssysteem foutinformatie naar de .NET I/O-methode. De methode vertaalt vervolgens de foutgegevens, meestal in de vorm van een foutcode, in een .NET-uitzonderingstype. In de meeste gevallen gebeurt dit door de foutcode rechtstreeks te vertalen in het bijbehorende uitzonderingstype; er wordt geen speciale toewijzing van de fout uitgevoerd op basis van de context van de methode-aanroep.

Op het Windows-besturingssysteem wordt bijvoorbeeld een methodeaanroep geretourneerd waarmee een foutcode van ERROR_FILE_NOT_FOUND (of 0x02) wordt toegewezen aan een FileNotFoundException, en een foutcode van ERROR_PATH_NOT_FOUND (of 0x03) wordt toegewezen aan een DirectoryNotFoundException.

De precieze omstandigheden waaronder het besturingssysteem bepaalde foutcodes retourneert, zijn echter vaak niet-gedocumenteerd of slecht gedocumenteerd. Als gevolg hiervan kunnen onverwachte uitzonderingen optreden. Omdat u bijvoorbeeld met een map werkt in plaats van een bestand, zou u verwachten dat het verstrekken van een ongeldig mappad aan de DirectoryInfo constructor een DirectoryNotFoundException. Het kan echter ook een FileNotFoundException.

Afhandeling van uitzonderingen in I/O-bewerkingen

Vanwege deze afhankelijkheid van het besturingssysteem kunnen identieke uitzonderingsvoorwaarden (zoals de fout in het voorbeeld van de map niet gevonden) resulteren in een I/O-methode die een van de hele klasse I/O-uitzonderingen genereert. Dit betekent dat bij het aanroepen van I/O-API's uw code moet worden voorbereid om de meeste of al deze uitzonderingen af te handelen, zoals wordt weergegeven in de volgende tabel:

Uitzonderingstype .NET Core/.NET 5+ .NET Framework
IOException Ja Ja
FileNotFoundException Ja Ja
DirectoryNotFoundException Ja Ja
DriveNotFoundException Ja Ja
PathTooLongException Ja Ja
OperationCanceledException Ja Ja
UnauthorizedAccessException Ja Ja
ArgumentException .NET Core 2.0 en eerder Ja
NotSupportedException No Ja
SecurityException Nr. Alleen beperkte vertrouwensrelatie

IOException verwerken

Omdat de basisklasse voor uitzonderingen in de System.IO naamruimte IOException ook wordt gegenereerd voor foutcodes die niet worden toegewezen aan een vooraf gedefinieerd uitzonderingstype. Dit betekent dat het kan worden gegenereerd door elke I/O-bewerking.

Belangrijk

Omdat IOException dit de basisklasse is van de andere uitzonderingstypen in de System.IO naamruimte, moet u in een catch blok verwerken nadat u de andere I/O-gerelateerde uitzonderingen hebt verwerkt.

Vanaf .NET Core 2.1 controleert validatie ook op pad correctheid (bijvoorbeeld om ervoor te zorgen dat ongeldige tekens niet aanwezig zijn in een pad) zijn verwijderd en genereert de runtime een uitzondering die is toegewezen aan een foutcode van een besturingssysteem in plaats van uit de eigen validatiecode. De meest waarschijnlijke uitzondering die in dit geval wordt gegenereerd, is een IOException, hoewel elk ander uitzonderingstype ook kan worden gegenereerd.

Houd er rekening mee dat u in uw uitzonderingsverwerkingscode altijd de IOException laatste moet afhandelen. Anders worden de catchblokken van afgeleide klassen niet geƫvalueerd, omdat dit de basisklasse is van alle andere IO-uitzonderingen.

In het geval van een IOException, kunt u aanvullende foutinformatie ophalen uit de eigenschap IOException.HResult . Als u de HResult-waarde wilt converteren naar een Win32-foutcode, wordt de bovenste 16 bits van de 32-bits waarde verwijderd. De volgende tabel bevat foutcodes die kunnen worden verpakt in een IOException.

HResult Constante Beschrijving
ERROR_SHARING_VIOLATION 32 De bestandsnaam ontbreekt of het bestand of de map wordt gebruikt.
ERROR_FILE_EXISTS 80 Het bestand bestaat al.
ERROR_INVALID_PARAMETER 87 Een argument dat aan de methode is opgegeven, is ongeldig.
ERROR_ALREADY_EXISTS 183 Het bestand of de map bestaat al.

U kunt deze verwerken met behulp van een When component in een catch-instructie, zoals in het volgende voorbeeld wordt weergegeven.

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

Zie ook