. Если исключение вызвано другими причинами, перевызываем исключение с помощью функции
>ioError
.
ПРИМЕЧАНИЕ. Функции >try
, >catch
, >ioError
и некоторые другие объявлены одновременно в модулях >System.IO.Error
(устаревший вариант) и >Control.Exception
(современный вариант), поэтому подключение обоих модулей (например, для использования предикатов исключений ввода-вывода) требует скрывающего или квалифицированного импорта либо же, как в предыдущем примере, явного указания импортируемых функций.
Итак, исключение, произошедшее в действии ввода-вывода >countLines
, но не по причине отсутствия файла, будет перехвачено и перевызвано в обработчике:
>$ ./linecount dont_exist.txt
>Файл не существует!
>$ ./linecount norights.txt
>linecount: noaccess.txt: openFile: permission denied (Permission denied)
Существует несколько предикатов, предназначенных для определения вида исключения ввода-вывода:
• >isAlreadyExistsError
(файл уже существует);
• >isDoesNotExistError
(файл не существует);
• >isAlreadyInUseError
(файл уже используется);
• >isFullError
(не хватает места на диске);
• >isEOFError
(достигнут конец файла);
• >isIllegalOperation
(выполнена недопустимая операция);
• >isPermissionError
(недостаточно прав доступа).
Пользуясь этими предикатами, можно написать примерно такой обработчик:
>handler :: IOException -> IO ()
>handler e
> | isDoesNotExistError e = putStrLn "Файл не существует!"
> | isPermissionError e = putStrLn "Не хватает прав доступа!"
> | isFullError e = putStrLn "Освободите место на диске!"
> | isIllegalOperation e = putStrLn "Караул! Спасите!"
> | otherwise = ioError e
Убедитесь, что вы перевызываете исключение, если оно не подходит под ваши критерии; в противном случае ваша программа иногда будет «падать» молча, что крайне нежелательно.
Модуль >System.IO.Error
также экспортирует функции, которые позволяют нам получать атрибуты исключения, например дескриптор файла, вызвавшего исключение, или имя файла. Все эти функции начинаются с префикса >ioe
; их полный список вы можете найти в документации. Скажем, мы хотим напечатать имя файла в сообщении об ошибке. Значение >fileName
, полученное при помощи функции >getArgs
, напечатать нельзя, потому что в обработчик передаётся только значение типа >IOException
и он не знает ни о чём другом. Функция зависит только от своих параметров. Но мы можем вызвать функцию >ioeGetFileName
, которая по переданному ей исключению возвращает >Maybe FilePath
. Функция пытается получить из значения исключения имя файла, если такое возможно. Давайте изменим обработчик так, чтобы он печатал полное имя файла, из-за которого возникло исключение (не забудьте включить функцию