2016-06-28 80 views
5

我在Haskell中編寫應用程序,並且如果readFilewriteFile失敗,想向用戶顯示有意義的錯誤消息。我目前正在使用Control.Exception.tryJust來捕捉IOError,並將它們轉換爲人類可讀的文本。糾正讀取文件和寫入文件異常的方法

但是,我很難弄清楚我應該捕捉哪些錯誤以及如何從中提取信息。例如,假設「/ bin」是一個目錄,「/ bin/ls」是一個文件,readFile "/bin"readFile "/bin/ls/asdf"都給出了「不恰當的類型」,但是(在我看來)它們是不同的錯誤。在第一種情況下,我可以通過處理目錄中的每個文件來恢復,而第二種更像是「不存在」類型的錯誤。

與前面的例子相比,似乎沒有捕獲「不恰當類型」錯誤的便攜方式。看着GHC.IO.ExceptionInappropriateType被標記爲GHC-only,所以我不能只在ioeGetErrorType模式匹配。我能模式匹配上ioeGetErrorString,但我不知道如果這些字符串總是在不同的平臺,編譯器,語言環境是相同的,等

總之,我的問題是:

  1. 哪些異常應該我趕上readFile/writeFile
  2. 一旦我有一個例外,我應該如何去從中提取信息?
  3. 是否有一種便攜的方式來捕獲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 
+1

我對Haskell基礎設施當前狀態的「便攜」異常並不樂觀。我們一直堅持單編譯模式多年。希望儘快改變。 – dfeuer

回答

3
  1. 我應該捕捉readFile/writeFile的哪些異常?

在OS X中,如果使用openFile其次是hGetContents代替readFile,那麼你會得到你所提到的情況下,不同的異常。

openFile "/bin/ls/asdf" ...將拋出「沒有這樣的文件或目錄」異常,而openFile "/bin" ...將拋出「不適當的類型」。

在Linux下,這兩個打開的調用都會拋出「不恰當的類型」異常。但是,可以通過ioe_errnoioe_description字段區分兩者:

import System.IO 
import GHC.IO.Exception 
import Control.Exception 

foo path = do 
    h <- openFile path ReadMode 
    hClose h 

show_ioe :: IOException -> IO() 
show_ioe e = do 
    putStrLn $ "errno: " ++ show (ioe_errno e) 
    putStrLn $ "description: " ++ ioe_description e 

bar path = foo path `catch` show_ioe 

樣品ghci的會話:

*Main> bar "/bin" 
errno: Nothing 
description: is a directory 
*Main> bar "/bin/ls/asd" 
errno: Just 20 
description: Not a directory 
  • 曾經有一個例外,我應該如何去從中提取信息?
  • 每個異常都有自己的結構。可以發現IOException的定義here

    要將字段訪問器納入範圍,您需要導入GHC.IO.Exception

    1. 是否有一種可移植的方式來捕獲僅限GHC的異常,如ValidityType?

    正如@dfeuer說,所有的實際目的GHC是此時唯一的Haskell的實現。

    更新運行您的程序

    結果。我沒有包含最後的結果,因爲我沒有一個只讀的文件系統來測試它,但我相信錯誤會是一樣的。

    ioe_filename = Just "/nonexistent", ioe_description = "No such file or directory", ioe_errno = Just 2 
    ioe_filename = Just "/dev/full", ioe_description = "Permission denied", ioe_errno = Just 13 
    ioe_filename = Just "/root", ioe_description = "is a directory", ioe_errno = Nothing 
    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 
    
    +0

    對於GNU/Linux,我仍然在GHC 7.10.3上使用System.IO.openFile獲得「不合適的類型」。 – Matthew

    +0

    我想確切的例外是操作系統依賴 - 然後我在OS X + GHC 7.10.2下測試它。更新了答案。 – ErikR

    +0

    但是 - 你會得到一個稍微不同的信息 - 「不是目錄」與「是目錄」 - 所以這是區分這兩者的一種方法。 – ErikR