纠正读取文件和写入文件异常的方法
我在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
- 我应该捕捉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的异常,如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
我对Haskell基础设施当前状态的“便携”异常并不乐观。我们一直坚持单编译模式多年。希望尽快改变。 – dfeuer