.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:
- System.IO.IOException, tüm System.IO özel durum türlerinin temel sınıfıdır. İşletim sisteminden dönüş kodları doğrudan başka bir özel durum türüyle eşlenemeyen hatalar için oluşturulur.
- System.IO.FileNotFoundException.
- System.IO.DirectoryNotFoundException.
- DriveNotFoundException.
- System.IO.PathTooLongException.
- System.OperationCanceledException.
- System.UnauthorizedAccessException.
- System.ArgumentException, .NET Framework ve .NET Core 2.0 ve önceki sürümlerde geçersiz yol karakterleri için oluşturulur.
- System.NotSupportedException, .NET Framework'te geçersiz iki nokta üst üste için oluşturulur.
- System.Security.SecurityException, sınırlı güven içinde çalışan ve yalnızca .NET Framework üzerinde gerekli izinlere sahip olmayan uygulamalar için oluşturulur. (.NET Framework'te tam güven varsayılandır.)
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