Sdílet prostřednictvím


Zpracování vstupně-výstupních chyb v .NET

Kromě výjimek, které mohou být vyvolány v jakémkoli volání metody (například OutOfMemoryException při zatížení systému nebo NullReferenceException kvůli chybě programátora), mohou metody systému souborů .NET vyvolat následující výjimky:

Mapování kódů chyb na výjimky

Vzhledem k tomu, že systém souborů je prostředek operačního systému, I/O metody v rozhraní .NET Core i rozhraní .NET Framework obklopují volání podkladového operačního systému. Pokud dojde k V/V chybě v kódu spuštěného operačním systémem, operační systém vrátí informace o chybě do V/V metody .NET. Metoda pak přeloží informace o chybě, obvykle ve formě kódu chyby, do typu výjimky .NET. Ve většině případů to dělá tak, že přímo přeloží kód chyby do odpovídajícího typu výjimky; neprovádí žádné zvláštní mapování chyby na základě kontextu volání metody.

Například v operačním systému Windows volání metody, která vrací kód chyby ERROR_FILE_NOT_FOUND (nebo 0x02), se mapuje na FileNotFoundException, a kód chyby ERROR_PATH_NOT_FOUND (nebo 0x03) se mapuje na DirectoryNotFoundException.

Přesné podmínky, za kterých operační systém vrací konkrétní kódy chyb, jsou však často nezdokumentovány nebo špatně zdokumentované. V důsledku toho může dojít k neočekávaným výjimkám. Například vzhledem k tomu, že pracujete s adresářem místo souboru, byste očekávali, že poskytnutí neplatné cesty k DirectoryInfo adresáři konstruktoru DirectoryNotFoundExceptionvyvolá . Může však také vyvolat FileNotFoundException.

Zpracování výjimek v vstupně-výstupních operacích

Kvůli závislosti na operačním systému mohou identické podmínky výjimek (například chyba nenalezeného adresáře v našem příkladu) vést k vyvolání jakékoli metody z celé třídy výjimek vstupně-výstupních operací. To znamená, že při volání rozhraní API pro vstupně-výstupní operace by měl být váš kód připravený na zpracování většiny nebo všech těchto výjimek, jak je znázorněno v následující tabulce:

Typ výjimky .NET Core/.NET 5 nebo novější .NET Framework
IOException Ano Ano
FileNotFoundException Ano Ano
DirectoryNotFoundException Ano Ano
DriveNotFoundException Ano Ano
PathTooLongException Ano Ano
OperationCanceledException Ano Ano
UnauthorizedAccessException Ano Ano
ArgumentException .NET Core 2.0 a starší Ano
NotSupportedException Ne Ano
SecurityException Ne Pouze omezená důvěra

Zpracování IOException

Jako základní třída výjimek v oboru názvů System.IO je IOException také vyvolána pro jakýkoli kód chyby, který se nemapuje na předdefinovaný typ výjimky. To znamená, že ji může vyvolat jakákoli vstupně-výstupní operace.

Důležité

Vzhledem k tomu, že IOException je základní třídou ostatních typů výjimek v oboru názvů System.IO, měli byste jej zpracovat v bloku catch poté, co zpracujete jiné výjimky související s operacemi vstupu a výstupu.

Kromě toho, od .NET Core 2.1, byly kontroly správnosti cesty (například k zajištění, že se v cestě nenacházejí neplatné znaky) zrušeny a modul runtime vyvolá výjimku mapovanou z kódu chyby operačního systému namísto z vlastního kódu ověřování. Nejpravděpodobnější výjimkou, která se v tomto případě vyvolá, je IOException, i když jakýkoli jiný typ výjimky může být vyvolán.

Všimněte si, že v kódu zpracování výjimek byste měli vždy zpracovat IOException poslední. Jinak, protože se jedná o základní třídu všech ostatních výjimek vstupně-výstupních operací, bloky catch odvozených tříd nebudou vyhodnoceny.

V případě IOException můžete získat další informace o chybě z vlastnosti IOException.HResult. Chcete-li převést hodnotu HResult na kód chyby Win32, odstraňte horních 16 bitů 32bitové hodnoty. Následující tabulka uvádí kódy chyb, které mohou být zabaleny do .IOException

HResult Konstanta Popis
Chyba sdílení – porušení pravidel 32 Název souboru chybí nebo se používá soubor nebo adresář.
CHYBA_SOUBOR_EXISTUJE 80 Soubor již existuje.
ERROR_INVALID_PARAMETER 87 Argument zadaný metodě je neplatný.
CHYBA_UŽ_EXISTUJE 183 Soubor nebo adresář již existuje.

Můžete je zpracovat pomocí When klauzule v příkazu catch, jak ukazuje následující příklad.

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

Viz také