我正在Haskell中编写一个应用程序,并希望在readFile
或writeFile
失败时向用户显示有意义的错误消息。我目前正在使用IOError
抓取Control.Exception.tryJust
并将其转换为人类可读的文字。
但是,我无法弄清楚应该捕获哪些错误以及如何从中提取信息。例如,假设“/ bin”是一个目录而“/ bin / ls”是一个文件,readFile "/bin"
和readFile "/bin/ls/asdf"
都给出“不合适的类型”,但(在我看来)它们是不同的错误。在第一个的情况下,我可以通过处理目录中的每个文件来恢复,而第二个更像是“不存在”类型的错误。
与前面的例子相比,似乎没有一种可移植的方式来捕获“不适当类型”错误。查看GHC.IO.Exception,InappropriateType
仅标记为GHC,因此我无法在ioeGetErrorType
上进行模式匹配。我可以在ioeGetErrorString
上进行模式匹配,但我不确定这些字符串在不同平台,编译器,语言环境等之间是否总是相同。
总之,我的问题是:
readFile
/ writeFile
?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
]
使用GHC 7.10.3的Debian Sid GNU / Linux上的输出是:
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
答案 0 :(得分:3)
- 我应该为readFile / writeFile捕获哪些异常?
醇>
在OS X下,如果您使用openFile
后跟hGetContents
而不是readFile
,那么您提到的案例会有不同的例外情况。
openFile "/bin/ls/asdf" ...
会抛出一个"没有这样的文件或目录"异常而openFile "/bin" ...
将抛出"不合适的类型"。
在Linux下,两个打开的电话都会抛出一个"不合适的类型"例外。但是,您可以通过ioe_errno
和ioe_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
。
- 是否有一种可移植的方式来捕获仅限GHC的异常,例如InappropriateType?
醇>
正如@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