首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >处理readFile和writeFile异常的正确方法

处理readFile和writeFile异常的正确方法
EN

Stack Overflow用户
提问于 2016-06-28 15:12:33
回答 1查看 1.8K关注 0票数 8

我正在用Haskell编写一个应用程序,如果readFilewriteFile失败,我希望向用户显示一条有意义的错误消息。目前,我正在用IOError捕获Control.Exception.tryJust,并将它们转换为人类可读的文本。

然而,我在找出应该捕获哪些错误以及如何从它们中提取信息时遇到了困难。例如,假设"/bin“是一个目录,而"/bin/ls”是一个文件,则readFile "/bin"readFile "/bin/ls/asdf"都提供“不适当的类型”,但是(我认为)它们是不同的错误。对于第一个文件,我可以通过处理目录中的每个文件来恢复,而第二个文件更像是“不存在”类型的错误。

与前面的例子相比,似乎没有一种可移植的方法来捕获“不适当的类型”错误。看看GHC.IO.ExceptionInappropriateType被标记为GHC--所以我不能只在ioeGetErrorType上匹配模式。我可以在ioeGetErrorString上进行模式匹配,但我不确定这些字符串在不同的平台、编译器、区域设置等之间是否总是相同的。

总括而言,我的问题是:

  1. readFile/writeFile应该捕获哪些异常
  2. 一旦我有了异常,我应该如何从它中提取信息?
  3. 是否有一种可移植的方法来捕获GHC专用的异常,如InappropriateType

更新:

基于@ErikR的回答,我使用以下Haskell程序查看GHC.IO.Exception.IOException字段:

代码语言:javascript
复制
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上的输出是:

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-29 02:11:53

  1. 对于readFile/writeFile,应该捕获哪些异常?

在OS下,如果您使用openFile,然后是hGetContents,而不是readFile,那么您所提到的情况就会有不同的异常。

openFile "/bin/ls/asdf" ...将抛出“没有这样的文件或目录”异常,而openFile "/bin" ...将抛出“不适当的类型”。

在Linux下,两个打开的调用都会引发“不适当的类型”异常。但是,您可以通过ioe_errnoioe_description字段区分两者:

代码语言:javascript
复制
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会话:

代码语言:javascript
复制
*Main> bar "/bin"
errno: Nothing
description: is a directory
*Main> bar "/bin/ls/asd"
errno: Just 20
description: Not a directory

  1. 一旦我有了异常,我应该如何从它中提取信息?

每个异常都有自己的结构。IOException的定义可以找到这里

要将字段访问器引入范围,您需要导入GHC.IO.Exception

  1. 是否有一种可移植的方法来捕获只有GHC的异常,如InappropriateType?

正如@dfeuer所说,就所有实际目的而言,GHC是目前唯一的Haskell实现。

更新

运行程序的结果。我没有包括最后的结果,因为我没有一个只读文件系统来测试它,但我确信错误将是相同的。

代码语言:javascript
复制
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
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38080021

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档