Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Помимо исключений, которые могут выбрасываться в любом вызове метода (например, OutOfMemoryException, когда система находится под нагрузкой или NullReferenceException, возникает из-за ошибки программиста), методы файловой системы .NET могут вызывать следующие исключения:
- System.IO.IOException— базовый класс всех System.IO типов исключений. Он выбрасывается для ошибок, коды возврата которых из операционной системы не сопоставляются ни с одним другим типом исключения.
- System.IO.FileNotFoundException.
- System.IO.DirectoryNotFoundException.
- DriveNotFoundException.
- System.IO.PathTooLongException.
- System.OperationCanceledException.
- System.UnauthorizedAccessException.
- System.ArgumentException, который вызывается при недопустимых символах пути в .NET Framework и в .NET Core 2.0 и предыдущих версиях.
- System.NotSupportedException, который выбрасывается для недопустимых двоеточий в .NET Framework.
- System.Security.SecurityException— выбрасывается для приложений, работающих в ограниченном доверии, которые не имеют необходимых разрешений, исключительно на платформе .NET Framework. (Полное доверие — это значение по умолчанию в .NET Framework.)
Сопоставление кодов ошибок с исключениями
Так как файловая система является ресурсом операционной системы, методы ввода-вывода как в .NET Core, так и в .NET Framework упаковывают вызовы базовой операционной системы. При возникновении ошибки ввода-вывода в коде, выполняемом операционной системой, операционная система возвращает сведения об ошибках в метод ввода-вывода .NET. Затем метод преобразует сведения об ошибке, как правило, в виде кода ошибки в тип исключения .NET. В большинстве случаев это делается путем непосредственного преобразования кода ошибки в соответствующий тип исключения; Он не выполняет специальное сопоставление ошибки на основе контекста вызова метода.
Например, в операционной системе Windows вызов метода, который возвращает код ERROR_FILE_NOT_FOUND
ошибки (или 0x02) сопоставляется с FileNotFoundException, а код ERROR_PATH_NOT_FOUND
ошибки (или 0x03) сопоставляется с DirectoryNotFoundException.
Однако точные условия, при которых операционная система возвращает определенные коды ошибок, часто недокументированы или плохо документированы. В результате могут возникнуть непредвиденные исключения. Например, поскольку вы работаете с каталогом, а не с файлом, можно ожидать, что предоставление недопустимого пути к каталогу через DirectoryInfo конструктор вызовет исключение DirectoryNotFoundException. Тем не менее, он также может вызвать FileNotFoundException.
Обработка исключений в операциях ввода-вывода
Из-за этой зависимости от операционной системы идентичные условия исключения (например, ошибка "каталог не найден" в нашем примере) могут привести к тому, что метод ввода-вывода может вызвать любое исключение из класса исключений ввода-вывода. Это означает, что при вызове API ввода-вывода код должен быть готов к обработке большинства или всех этих исключений, как показано в следующей таблице:
Тип исключения | .NET Core/.NET 5+ | Платформа .NET Framework |
---|---|---|
IOException | Да | Да |
FileNotFoundException | Да | Да |
DirectoryNotFoundException | Да | Да |
DriveNotFoundException | Да | Да |
PathTooLongException | Да | Да |
OperationCanceledException | Да | Да |
UnauthorizedAccessException | Да | Да |
ArgumentException | .NET Core 2.0 и более ранних версий | Да |
NotSupportedException | нет | Да |
SecurityException | нет | Только ограниченное доверие |
Обработка IOException
В качестве базового класса для исключений в пространстве имен System.IO класс IOException также создается для любого кода ошибки, который не сопоставляется с предопределенным типом исключения. Это означает, что она может быть вызвана любой операцией ввода-вывода.
Это важно
Так как IOException является базовым классом других типов исключений в System.IO пространстве имен, следует обрабатывать в catch
блоке после обработки других исключений, связанных с вводом-выводом.
Кроме того, начиная с .NET Core 2.1, проверки правильности пути (например, для того чтобы убедиться, что в пути отсутствуют недопустимые символы) были удалены, и теперь среда выполнения генерирует исключение, сопоставленное с кодом ошибки операционной системы, а не с собственным кодом проверки. Скорее всего, в этом случае будет выброшено исключение IOException, хотя может быть создан и любой другой тип исключения.
Обратите внимание, что в коде обработки исключений следует всегда обрабатывать IOException в последнюю очередь. В противном случае, поскольку он является базовым классом всех других исключений ввода-вывода, блоки catch производных классов не будут оцениваться.
В случае возникновения IOException ошибки можно получить дополнительные сведения об ошибке из свойства IOException.HResult. Чтобы преобразовать значение HResult в код ошибки Win32, вы удаляете верхние 16 битов 32-разрядного значения. В следующей таблице перечислены коды ошибок, которые могут быть упакованы в .IOException
HResult | Постоянный | Описание |
---|---|---|
ERROR_SHARING_VIOLATION (Ошибка совместного использования) | 32 | Имя файла отсутствует или используется файл или каталог. |
ОШИБКА_ФАЙЛ_СУЩЕСТВУЕТ | 80 | Файл уже существует. |
ОШИБКА_НЕПРАВИЛЬНЫЙ_ПАРАМЕТР | 87 | Аргумент, предоставленный методу, недопустим. |
Уже существует ошибка | 183 | Файл или каталог уже существует. |
Их можно обрабатывать с помощью When
предложения в инструкции catch, как показано в следующем примере.
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