我在Haskell中編寫應用程序,並且如果readFile
或writeFile
失敗,想向用戶顯示有意義的錯誤消息。我目前正在使用Control.Exception.tryJust
來捕捉IOError
,並將它們轉換爲人類可讀的文本。糾正讀取文件和寫入文件異常的方法
但是,我很難弄清楚我應該捕捉哪些錯誤以及如何從中提取信息。例如,假設「/ bin」是一個目錄,「/ bin/ls」是一個文件,readFile "/bin"
和readFile "/bin/ls/asdf"
都給出了「不恰當的類型」,但是(在我看來)它們是不同的錯誤。在第一種情況下,我可以通過處理目錄中的每個文件來恢復,而第二種更像是「不存在」類型的錯誤。
與前面的例子相比,似乎沒有捕獲「不恰當類型」錯誤的便攜方式。看着GHC.IO.Exception,InappropriateType
被標記爲GHC-only,所以我不能只在ioeGetErrorType
模式匹配。我能模式匹配上ioeGetErrorString
,但我不知道如果這些字符串總是在不同的平臺,編譯器,語言環境是相同的,等
總之,我的問題是:
- 哪些異常應該我趕上
readFile
/writeFile
? - 一旦我有一個例外,我應該如何去從中提取信息?
- 是否有一種便攜的方式來捕獲GHC唯一的例外,如
InappropriateType
?
更新:
基於@ ErikR的回答我看的GHC.IO.Exception.IOException
具有以下的Haskell程序中的字段:
import Control.Exception (try)
import GHC.IO.Exception (IOException(..))
import qualified Data.ByteString as B
main :: IO()
main = do
try (readFile "/nonexistent") >>= printException
try (writeFile "/dev/full" " ") >>= printException
try (readFile "/root") >>= printException
try (readFile "/bin") >>= printException
try (writeFile "/bin" "") >>= printException
try (readFile "/bin/ls/asdf") >>= printException
try (writeFile "/bin/ls/asdf" "") >>= printException
try (B.readFile "/dev/null") >>= printException
-- I have /media/backups mounted as read-only. Substitute your own read-only
-- filesystem for this one
try (writeFile "/media/backups/asdf" "") >>= printException
printException :: Either IOError a -> IO()
printException (Right _) = putStrLn "No exception caught"
printException (Left e) = putStrLn $ concat [ "ioe_filename = "
, show $ ioe_filename e
, ", ioe_description = "
, show $ ioe_description e
, ", ioe_errno = "
, show $ ioe_errno e
]
在Debian希德GNU/Linux的輸出與GHC 7.10.3是:
ioe_filename = Just "/nonexistent", ioe_description = "No such file or directory", ioe_errno = Just 2
ioe_filename = Just "/dev/full", ioe_description = "No space left on device", ioe_errno = Just 28
ioe_filename = Just "/root", ioe_description = "Permission denied", ioe_errno = Just 13
ioe_filename = Just "/bin", ioe_description = "is a directory", ioe_errno = Nothing
ioe_filename = Just "/bin", ioe_description = "Is a directory", ioe_errno = Just 21
ioe_filename = Just "/bin/ls/asdf", ioe_description = "Not a directory", ioe_errno = Just 20
ioe_filename = Just "/bin/ls/asdf", ioe_description = "Not a directory", ioe_errno = Just 20
ioe_filename = Just "/dev/null", ioe_description = "not a regular file", ioe_errno = Nothing
ioe_filename = Just "/media/backups/asdf", ioe_description = "Read-only file system", ioe_errno = Just 30
我對Haskell基礎設施當前狀態的「便攜」異常並不樂觀。我們一直堅持單編譯模式多年。希望儘快改變。 – dfeuer