.NET'te G/Ç hatalarını işleme

.NET dosya sistemi yöntemleri, herhangi bir OutOfMemoryException yöntem çağrısında oluşturulabilecek özel durumlara ek olarak (örneğin, bir sistem stresli olduğunda veya NullReferenceException programcı hatası nedeniyle), aşağıdaki özel durumları oluşturabilir:

Hata kodlarını özel durumlarla eşleme

Dosya sistemi bir işletim sistemi kaynağı olduğundan hem .NET Core hem de .NET Framework'teki G/Ç yöntemleri, temel işletim sistemine çağrılar gönderir. İşletim sistemi tarafından yürütülen kodda G/Ç hatası oluştuğunda, işletim sistemi hata bilgilerini .NET G/Ç yöntemine döndürür. Yöntemi daha sonra genellikle hata kodu biçimindeki hata bilgilerini bir .NET özel durum türüne çevirir. Çoğu durumda hata kodunu doğrudan ilgili özel durum türüne çevirerek bunu yapar; yöntem çağrısının bağlamını temel alarak hatanın özel eşlemesini gerçekleştirmez.

Örneğin, Windows işletim sisteminde hata kodu ERROR_FILE_NOT_FOUND (veya 0x02) döndüren bir yöntem çağrısı ile FileNotFoundExceptionve hata kodu ERROR_PATH_NOT_FOUND (veya 0x03) ile DirectoryNotFoundExceptioneşleşir.

Ancak, işletim sisteminin belirli hata kodlarını döndürdüğü kesin koşullar genellikle belgelenmemiş veya kötü belgelenmiştir. Sonuç olarak beklenmeyen özel durumlar oluşabilir. Örneğin, dosya yerine bir dizinle çalıştığınız için, oluşturucuya geçersiz bir dizin yolu sağlamanın bir DirectoryNotFoundExceptionoluşturmasını DirectoryInfo beklersiniz. Ancak, bir FileNotFoundExceptionde atabilir.

G/Ç işlemlerinde özel durum işleme

İşletim sistemine olan bu dayanıklılık nedeniyle, özdeş özel durum koşulları (örneğimizde dizin bulunamadı hatası gibi) G/Ç yönteminin G/Ç özel durumlarının tüm sınıfından birini oluşturmasını sağlayabilir. Bu, G/Ç API'lerini çağırırken kodunuzun aşağıdaki tabloda gösterildiği gibi bu özel durumların çoğunu veya tümünü işlemeye hazır olması gerektiği anlamına gelir:

Özel durum türü .NET Core/.NET 5+ .NET Framework
IOException Yes Evet
FileNotFoundException Evet Evet
DirectoryNotFoundException Evet Evet
DriveNotFoundException Evet Evet
PathTooLongException Evet Evet
OperationCanceledException Evet Evet
UnauthorizedAccessException Evet Yes
ArgumentException .NET Core 2.0 ve öncesi Yes
NotSupportedException Hayı Evet
SecurityException Hayır Yalnızca sınırlı güven

IOException'ın işlenmesi

Ad alanında System.IO özel durumlar için temel sınıf olarak, IOException önceden tanımlanmış bir özel durum türüne eşlenmeyen herhangi bir hata kodu için de oluşturulur. Bu, herhangi bir G/Ç işlemi tarafından oluşturulabileceği anlamına gelir.

Önemli

Ad alanında diğer özel durum türlerinin System.IO temel sınıfı olduğundanIOException, G/Ç ile ilgili diğer özel durumları işledikten sonra bir catch blokta işlemeniz gerekir.

Buna ek olarak, .NET Core 2.1'den başlayarak doğrulama, yol doğruluğunu denetler (örneğin, bir yolda geçersiz karakterlerin bulunmadığından emin olmak için) kaldırılmıştır ve çalışma zamanı kendi doğrulama kodu yerine işletim sistemi hata kodundan eşlenmiş bir özel durum oluşturur. Bu durumda oluşturulabilecek en olası özel durum bir IOException'dir, ancak başka bir özel durum türü de oluşturulabilir.

Özel durum işleme kodunuzda her zaman sonuncuyu IOException işlemeniz gerektiğini unutmayın. Aksi takdirde, diğer tüm GÇ özel durumlarının temel sınıfı olduğundan, türetilmiş sınıfların catch blokları değerlendirilmez.

durumundaIOException, IOException.HResult özelliğinden ek hata bilgileri alabilirsiniz. HResult değerini Win32 hata koduna dönüştürmek için, 32 bit değerin üst 16 bitini çıkarırsınız. Aşağıdaki tabloda, içinde IOExceptionsarmalanabilecek hata kodları listelenmektedir.

HResult Sabit Açıklama
ERROR_SHARING_VIOLATION 32 Dosya adı eksik veya dosya veya dizin kullanımda.
ERROR_FILE_EXISTS 80 Dosya zaten var.
ERROR_INVALID_PARAMETER 87 yöntemine sağlanan bağımsız değişken geçersiz.
ERROR_ALREADY_EXISTS 183 Dosya veya dizin zaten var.

Aşağıdaki örnekte gösterildiği gibi, bunları catch deyimindeki bir yan tümcesi kullanarak When işleyebilirsiniz.

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

Ayrıca bkz.