System.IO.Error — 입출력 오류 처리
System.IO.Error — 입출력 오류 처리
System.IO.Error은 I/O 연산의 오류를 다루는 모듈이에요. IO 모나드에서 발생하는 오류는 IOError 타입으로 표현되는데, 이 모듈은 그러한 오류를 만들고, 분류하고, 속성을 조회하고, 던지고, 잡는 기능을 제공해요. 파일이 없거나, 장치가 가득 찼거나, 권한이 없는 등의 상황을 프로그램에서 어떻게 인식하고 대처할지 결정하는 데 쓰여요.
본문
이 모듈이 내보내는 것들은 다음과 같아요.
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를 받는 핸들러를 설정해요. IOError는 catch가 설정한 가장 최근의 핸들러가 잡아요. 이 핸들러들은 선택적이지 않아요: 모든 IOError가 잡혀요. 원하지 않는 예외는 핸들러 안에서 다시 던져서(재발생) 예외 전파를 명시적으로 제공해야 해요. 예를 들어,
f = catch g (\e -> if IO.isEOFError e then return [] else ioError e)
에서 함수 f는 g에서 파일 끝 예외(참고: isEOFError)가 발생하면 []를 돌려주고, 그 외에는 예외를 다음 바깥 핸들러로 전파해요. 예외가 메인 프로그램 밖으로 전파되면, Haskell 시스템은 연관된 IOError 값을 출력하고 프로그램을 종료해요.
try :: IO a -> IO (Either IOError a)
동작의 결과로 오류가 발생하면 그 값을 목록의 왼쪽(Left)에, 성공하면 값을 오른쪽(Right)에 담아 돌려줘요.