Freigeben über


Behandeln von E/A-Fehlern in .NET

Zusätzlich zu den Ausnahmen, die in jedem Methodenaufruf ausgelöst werden können (z OutOfMemoryException . B. wenn ein System betont wird oder ein Fehler aufgrund eines NullReferenceException Programmiererfehlers auftritt), können .NET-Dateisystemmethoden die folgenden Ausnahmen auslösen:

Zuordnen von Fehlercodes zu Ausnahmen

Da das Dateisystem eine Betriebssystemressource ist, schließen I/O-Methoden sowohl in .NET Core als auch .NET Framework Aufrufe an das zugrunde liegende Betriebssystem um. Wenn ein E/A-Fehler im vom Betriebssystem ausgeführten Code auftritt, gibt das Betriebssystem Fehlerinformationen an die .NET-E/A-Methode zurück. Die Methode übersetzt dann die Fehlerinformationen, in der Regel in Form eines Fehlercodes, in einen .NET-Ausnahmetyp. In den meisten Fällen erfolgt dies, indem der Fehlercode direkt in den entsprechenden Ausnahmetyp übersetzt wird; sie führt keine spezielle Zuordnung des Fehlers basierend auf dem Kontext des Methodenaufrufs durch.

Im Windows-Betriebssystem wird beispielsweise ein Methodenaufruf, der einen Fehlercode ERROR_FILE_NOT_FOUND (oder 0x02) zurückgibt, einem FileNotFoundException, und einem Fehlercode (ERROR_PATH_NOT_FOUNDoder 0x03) zugeordnet.DirectoryNotFoundException

Allerdings sind die genauen Bedingungen, unter denen das Betriebssystem bestimmte Fehlercodes zurückgibt, häufig nicht dokumentiert oder schlecht dokumentiert. Daher können unerwartete Ausnahmen auftreten. Da Sie z. B. nicht mit einer Datei, sondern mit einem Verzeichnis arbeiten, erwarten Sie, dass die Bereitstellung eines ungültigen Verzeichnispfads zum DirectoryInfo Konstruktor einen DirectoryNotFoundException. Es kann jedoch auch einen FileNotFoundException.

Ausnahmebehandlung in E/A-Vorgängen

Aufgrund dieser Abhängigkeit vom Betriebssystem können identische Ausnahmebedingungen (z. B. das Verzeichnis, das in unserem Beispiel nicht gefunden wurde) dazu führen, dass eine E/A-Methode eine der gesamten E/A-Ausnahmen auslöst. Dies bedeutet, dass Ihr Code beim Aufrufen von E/A-APIs darauf vorbereitet sein sollte, die meisten oder alle diese Ausnahmen zu verarbeiten, wie in der folgenden Tabelle gezeigt:

Ausnahmetyp .NET Core/.NET 5+ .NET Framework (Englisch)
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 und früher Ja
NotSupportedException Nein Ja
SecurityException Nein Nur eingeschränkte Vertrauensstellung

Behandeln von IOException

Als Basisklasse für Ausnahmen im System.IO Namespace wird auch für fehlercode ausgelöst, IOException der keinem vordefinierten Ausnahmetyp zugeordnet ist. Dies bedeutet, dass sie von jedem E/A-Vorgang ausgelöst werden kann.

Von Bedeutung

Da IOException es sich um die Basisklasse der anderen Ausnahmetypen im System.IO Namespace handelt, sollten Sie in einem catch Block behandeln, nachdem Sie die anderen I/O-bezogenen Ausnahmen behandelt haben.

Außerdem wird ab .NET Core 2.1 überprüft die Überprüfung auf die Pfadkorrektur (z. B. um sicherzustellen, dass ungültige Zeichen nicht in einem Pfad vorhanden sind) entfernt, und die Laufzeit löst eine Ausnahme aus, die einem Betriebssystemfehlercode zugeordnet ist, und nicht aus seinem eigenen Gültigkeitsprüfungscode. Die wahrscheinlichste Ausnahme, die in diesem Fall ausgelöst wird, ist ein IOException, obwohl jeder andere Ausnahmetyp auch ausgelöst werden kann.

Beachten Sie, dass Sie in Ihrem Ausnahmebehandlungscode immer die IOException letzte behandeln sollten. Andernfalls werden die Catch-Blöcke abgeleiteter Klassen nicht ausgewertet, da es sich um die Basisklasse aller anderen E/A-Ausnahmen handelt.

Bei einem IOExceptionFehler können Sie zusätzliche Fehlerinformationen aus der IOException.HResult-Eigenschaft abrufen. Um den HResult-Wert in einen Win32-Fehlercode zu konvertieren, entfernen Sie die oberen 16 Bit des 32-Bit-Werts. In der folgenden Tabelle sind Fehlercodes aufgeführt, die in ein IOException.

HRESULT Dauerhaft BESCHREIBUNG
ERROR_SHARING_VIOLATION (Freigabeverletzung) 32 Der Dateiname fehlt, oder die Datei oder das Verzeichnis wird verwendet.
ERROR_FILE_EXISTS 80 Die Datei ist bereits vorhanden.
FEHLER_UNGÜLTIGER_PARAMETER 87 Ein argument, das an die Methode übergeben wird, ist ungültig.
FEHLER_BEREITS_VORHANDEN 183 Die Datei oder das Verzeichnis ist bereits vorhanden.

Sie können diese mithilfe einer When Klausel in einer Catch-Anweisung behandeln, wie im folgenden Beispiel gezeigt.

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

Siehe auch