다음을 통해 공유


.NET에서 I/O 오류 처리

메서드 호출에서 발생할 수 있는 예외(시스템에 과부하가 걸릴 때 발생하는 OutOfMemoryException 또는 프로그래머 오류로 인한 NullReferenceException 등) 외에도, .NET 파일 시스템 메서드는 다음과 같은 예외를 던질 수 있습니다.

오류 코드를 예외에 매핑

파일 시스템은 운영 체제 리소스이므로 .NET Core 및 .NET Framework의 I/O 메서드는 기본 운영 체제에 대한 호출을 래핑합니다. 운영 체제에서 실행하는 코드에서 I/O 오류가 발생하면 운영 체제는 .NET I/O 메서드에 오류 정보를 반환합니다. 그런 다음, 메서드는 오류 정보(일반적으로 오류 코드 형식)를 .NET 예외 형식으로 변환합니다. 대부분의 경우 오류 코드를 해당 예외 형식으로 직접 변환하여 이 작업을 수행합니다. 메서드 호출의 컨텍스트에 따라 오류의 특별한 매핑을 수행하지 않습니다.

예를 들어 Windows 운영 체제에서 오류 코드 ERROR_FILE_NOT_FOUND (또는 0x02)를 반환하는 메서드 호출은 FileNotFoundException에 매핑되고, 오류 코드 ERROR_PATH_NOT_FOUND (또는 0x03)는 DirectoryNotFoundException에 매핑됩니다.

그러나 운영 체제에서 특정 오류 코드를 반환하는 정확한 조건은 문서화되지 않았거나 제대로 문서화되지 않은 경우가 많습니다. 따라서 예기치 않은 예외가 발생할 수 있습니다. 예를 들어, 파일이 아닌 디렉터리로 작업하는 경우 DirectoryInfo 생성자에 잘못된 디렉터리 경로를 제공하면 DirectoryNotFoundException 예외가 발생합니다. 그러나 FileNotFoundException을(를) 던질 수도 있습니다.

I/O 작업의 예외 처리

운영 체제에 대한 이러한 의존으로 인해 동일한 예외 조건(예: 예제에서 디렉터리를 찾을 수 없음 오류)으로 인해 I/O 메서드가 I/O 예외의 전체 클래스 중 하나를 throw할 수 있습니다. 즉, I/O 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가 발생됩니다. 즉, 모든 I/O 작업에서 발생할 수 있습니다.

중요합니다

IOException 네임스페이스에 있는 System.IO 다른 예외 형식의 기본 클래스이므로 다른 I/O 관련 예외를 catch 처리한 후 블록에서 처리해야 합니다.

또한 .NET Core 2.1부터 유효성 검사에서 경로 정확성(예: 경로에 잘못된 문자가 없는지 확인)이 제거되었으며 런타임은 자체 유효성 검사 코드가 아닌 운영 체제 오류 코드에서 매핑된 예외를 throw합니다. 이 경우 throw될 가능성이 가장 큰 예외는 IOException이며, 다른 예외 형식도 throw될 수 있습니다.

예외 처리 코드에서는 항상 마지막을 IOException 처리해야 합니다. 그렇지 않으면 다른 모든 IO 예외의 기본 클래스이므로 파생 클래스의 catch 블록은 평가되지 않습니다.

IOException경우 IOException.HResult 속성에서 추가 오류 정보를 가져올 수 있습니다. HResult 값을 Win32 오류 코드로 변환하려면 32비트 값의 상위 16비트를 제거합니다. 다음 표에서는 IOException에 래핑될 수 있는 오류 코드를 나열합니다.

HResult 변하지 않는 것 설명
공유 위반 오류 32 파일 이름이 없거나 파일 또는 디렉터리가 사용 중입니다.
오류_파일_존재함 80 파일이 이미 있습니다.
ERROR_INVALID_PARAMETER (잘못된 매개변수) 87 메서드에 제공된 인수가 잘못되었습니다.
오류_이미_존재함 183 파일 또는 디렉터리가 이미 있습니다.

catch 문에서 When 절을 사용하여 다음 예제와 같이 항목을 처리할 수 있습니다.

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

참고하십시오