Aracılığıyla paylaş


.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ı FileNotFoundException ile ve hata kodu ERROR_PATH_NOT_FOUND (veya 0x03) ise DirectoryNotFoundException ile eş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 DirectoryInfo oluşturmasını DirectoryNotFoundException beklersiniz. Ancak bir FileNotFoundException oluşturabilir.

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

İşletim sistemine olan bu bağımlılık nedeniyle, özdeş istisna koşulları (örneğimizde dizin bulunamadı hatası gibi) G/Ç yönteminin her türlü G/Ç istisnasını fırlatmasına neden olabilir. 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 Çerçevesi
IOException Evet Evet
FileNotFoundException Evet Evet
DirectoryNotFoundException Evet Evet
DriveNotFoundException Evet Evet
PathTooLongException Evet Evet
OperationCanceledException Evet Evet
UnauthorizedAccessException Evet Evet
ArgumentException .NET Core 2.0 ve öncesi Evet
NotSupportedException Hayı Evet
SecurityException Hayı Yalnızca sınırlı güven

IOException'ın işlenmesi

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

Önemli

Diğer özel durum türlerinin IOException ad alanında System.IO temel sınıfı olduğundan, G/Ç ile ilgili diğer özel durumları ele aldıktan sonra bir catch blokta tutmanız gerekir.

Buna ek olarak, .NET Core 2.1'den itibaren, yol doğruluğunu kontrol eden doğrulama denetimleri (örneğin, bir yolda geçersiz karakterlerin olmadığından emin olmak için) kaldırılmıştır ve çalışma zamanı kendi doğrulama kodu yerine işletim sistemi hata kodundan oluşturulan bir istisna meydana getirir. 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, IOException her zaman en son ele almanız gerektiğini unutmayın. Aksi takdirde, diğer tüm Girdi/Çıktı (GÇ) özel durumlarının temel sınıfı olduğundan, türetilmiş sınıfların yakalama blokları değerlendirilmez.

Bir IOException durumunda, 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 IOException sarmalanmış olabilecek hata kodları listelenmektedir.

HResult Sabit Açıklama
PAYLAŞIM İHLALİ HATASI 32 Dosya adı eksik veya dosya veya dizin kullanımda.
DOSYA_MEVCUT_HATASI 80 Dosya zaten var.
HATA_GEÇERSİZ_PARAMETRE 87 yöntemine sağlanan bağımsız değişken geçersiz.
ERROR_ALREADY_EXISTS 183 Dosya veya dizin zaten var.

Bunları, catch deyimindeki bir When yan tümcesi kullanarak işleyebilirsiniz, aşağıdaki örnek bunu göstermektedir.

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 bakınız