System.IO.Error — 입출력 오류 처리

System.IO.Error — 입출력 오류 처리

System.IO.Error은 I/O 연산의 오류를 다루는 모듈이에요. IO 모나드에서 발생하는 오류는 IOError 타입으로 표현되는데, 이 모듈은 그러한 오류를 만들고, 분류하고, 속성을 조회하고, 던지고, 잡는 기능을 제공해요. 파일이 없거나, 장치가 가득 찼거나, 권한이 없는 등의 상황을 프로그램에서 어떻게 인식하고 대처할지 결정하는 데 쓰여요.

출처: Haskell 2010 언어 리포트

본문

이 모듈이 내보내는 것들은 다음과 같아요.

module System.IO.Error (

    IOError,  userError,  mkIOError,  annotateIOError,  isAlreadyExistsError,

    isDoesNotExistError,  isAlreadyInUseError,  isFullError,  isEOFError,

    isIllegalOperation,  isPermissionError,  isUserError,  ioeGetErrorString,

    ioeGetHandle,  ioeGetFileName,  IOErrorType,  alreadyExistsErrorType,

    doesNotExistErrorType,  alreadyInUseErrorType,  fullErrorType,

    eofErrorType,  illegalOperationErrorType,  permissionErrorType,

    userErrorType,  ioError,  catch,  try

  ) where

42.1 I/O 오류

type IOError = IOError

IOError 타입의 오류들은 IO 모나드에서 사용돼요. 이것은 추상 타입이며, System.IO.Error 모듈이 IOError 값을 조회하고 구성하는 함수를 제공해요.

userError :: String -> IOError

오류를 설명하는 문자열로 IOError 값을 구성해요. Monad 클래스의 IO 인스턴스의 fail 메서드는 userError를 던지는데, 다음과 같아요.

 instance Monad IO where

   ...

   fail s = ioError (userError s)
mkIOError :: IOErrorType   -> String -> Maybe Handle -> Maybe FilePath -> IOError

주어진 타입의 IOError를 구성하는데, 두 번째 인자는 오류 위치를 설명하고, 세 번째·네 번째 인자는 해당하는 경우 오류가 관련된 파일의 핸들과 파일 경로를 담아요.

annotateIOError :: IOError   -> String -> Maybe Handle -> Maybe FilePath -> IOError

IOError에 위치 설명을 추가하고, 어쩌면 파일 경로와 파일 핸들을 추가해요. 파일 핸들이나 파일 경로 중 주어지지 않은 것이 있으면 IOError의 대응 값은 그대로 남아요.

42.1.1 I/O 오류 분류하기

isAlreadyExistsError :: IOError -> Bool

인자 중 하나가 이미 존재하기 때문에 I/O 연산이 실패했음을 나타내는 오류예요.

isDoesNotExistError :: IOError -> Bool

인자 중 하나가 존재하지 않기 때문에 I/O 연산이 실패했음을 나타내는 오류예요.

isAlreadyInUseError :: IOError -> Bool

인자 중 하나가 일회용(단일 사용) 리소스인데 이미 사용 중이기 때문에 I/O 연산이 실패했음을 나타내는 오류예요(예: 같은 파일을 쓰기 위해 두 번 여는 경우 이런 오류가 날 수 있어요).

isFullError :: IOError -> Bool

장치가 가득 차서 I/O 연산이 실패했음을 나타내는 오류예요.

isEOFError :: IOError -> Bool

파일 끝에 도달해서 I/O 연산이 실패했음을 나타내는 오류예요.

isIllegalOperation :: IOError -> Bool

연산이 불가능해서 I/O 연산이 실패했음을 나타내는 오류예요. IO 결과를 반환하는 어떤 계산도 isIllegalOperation으로 실패할 수 있어요. 어떤 경우에는 구현이 가능한 오류 원인들을 구분할 수 없을 수도 있어요. 그런 경우에는 isIllegalOperation으로 실패해야 해요.

isPermissionError :: IOError -> Bool

사용자에게 그 연산을 수행할 충분한 운영체제 권한이 없기 때문에 I/O 연산이 실패했음을 나타내는 오류예요.

isUserError :: IOError -> Bool

userError를 사용해 구성된 프로그래머 정의 오류예요.

42.1.2 I/O 오류의 속성

ioeGetErrorString :: IOError -> String

오류를 설명하는 문자열을 돌려줘요.

ioeGetHandle :: IOError -> Maybe Handle

오류와 관련된 핸들(있다면)을 돌려줘요.

ioeGetFileName :: IOError -> Maybe FilePath

오류와 관련된 파일 경로(있다면)를 돌려줘요.

42.2 I/O 오류의 타입

data IOErrorType

IOError 변종에 대한 값을 담는 추상 타입이에요.

instance Eq IOErrorType  instance Show IOErrorType
alreadyExistsErrorType :: IOErrorType

인자 중 하나가 이미 존재하기 때문에 연산이 실패한 I/O 오류예요.

doesNotExistErrorType :: IOErrorType

인자 중 하나가 존재하지 않기 때문에 연산이 실패한 I/O 오류예요.

alreadyInUseErrorType :: IOErrorType

인자 중 하나가 일회용 리소스인데 이미 사용 중이기 때문에 연산이 실패한 I/O 오류예요.

fullErrorType :: IOErrorType

장치가 가득 차서 연산이 실패한 I/O 오류예요.

eofErrorType :: IOErrorType

파일 끝에 도달해서 연산이 실패한 I/O 오류예요.

illegalOperationErrorType :: IOErrorType

연산이 불가능한 I/O 오류예요.

permissionErrorType :: IOErrorType

사용자에게 그 연산을 수행할 충분한 운영체제 권한이 없기 때문에 연산이 실패한 I/O 오류예요.

userErrorType :: IOErrorType

프로그래머가 정의한 I/O 오류예요.

42.3 I/O 오류 던지기와 잡기

ioError :: IOError -> IO a

IO 모나드에서 IOError를 던져요.

catch :: IO a -> (IOError -> IO a) -> IO a

catch 함수는 catch가 보호하는 동작에서 던져진 IOError를 받는 핸들러를 설정해요. IOErrorcatch가 설정한 가장 최근의 핸들러가 잡아요. 이 핸들러들은 선택적이지 않아요: 모든 IOError가 잡혀요. 원하지 않는 예외는 핸들러 안에서 다시 던져서(재발생) 예외 전파를 명시적으로 제공해야 해요. 예를 들어,

 f = catch g (\e -> if IO.isEOFError e then return [] else ioError e)

에서 함수 fg에서 파일 끝 예외(참고: isEOFError)가 발생하면 []를 돌려주고, 그 외에는 예외를 다음 바깥 핸들러로 전파해요. 예외가 메인 프로그램 밖으로 전파되면, Haskell 시스템은 연관된 IOError 값을 출력하고 프로그램을 종료해요.

try :: IO a -> IO (Either IOError a)

동작의 결과로 오류가 발생하면 그 값을 목록의 왼쪽(Left)에, 성공하면 값을 오른쪽(Right)에 담아 돌려줘요.

더 알아보기 (Learn more)