2013-04-27 7 views
3

hGetContents返回一个懒惰的String对象,该对象可用于纯功能性代码中从文件句柄读取。如果在读取此懒惰字符串时发生I/O异常,则会默认关闭基础文件句柄,并且不会将其他字符添加到懒惰字符串中。从hGetContents中检测延迟字符串中的I/O异常?

如何检测此I/O异常?

作为具体的例子,考虑下面的程序:

import System.IO -- for stdin 

lengthOfFirstLine :: String -> Int 
lengthOfFirstLine "" = 0 
lengthOfFirstLine s = (length . head . lines) s 

main :: IO() 
main = do 
    lazyStdin <- hGetContents stdin 
    print (lengthOfFirstLine lazyStdin) 

如果读取该文件的第一行出现异常,直到I/O异常发生此程序将打印的字符数。相反,我希望程序崩溃并发生相应的I/O异常。如何修改这个程序来实现这种行为?

编辑:一旦hGetContents实施的仔细检查,看来该I/O异常不会被忽略,但通过调用纯功能的代码,任何IO代码发生触发的评价,这有机会,而冒泡然后处理它。 (我之前并不知道纯函数代码可能会引发异常。)因此,这个问题是一个误解。

旁白:如果这种特殊的行为是凭经验验证的话,那将是最好的。不幸的是,很难模拟低级别的I/O错误。

回答

0

另外:如果这种特殊行为通过经验验证 将是最好的。不幸的是,很难模拟低级I/O 错误。

我在想同样的事情,发现了这个老问题,并决定做一个实验。

我跑在Windows这个小程序,监听连接,并读取它懒洋洋地:

import System.IO 
import Network 
import Control.Concurrent 

main :: IO() 
main = withSocketsDo (do 
    socket <- listenOn (PortNumber 19999) 
    print "created socket" 
    (h,_,_) <- accept socket 
    print "accepted connection" 
    contents <- hGetContents h 
    print contents) 

从一台Linux机器,我打开使用nc连接:

nc -v mymachine 19999 
Connection to mymachine 19999 port [tcp/*] succeeded! 

而且然后使用Windows Sysinternal的TCPView实用程序强制关闭连接。结果是:

Main.exe: <socket: 348>: hGetContents: failed (Unknown error) 

看起来I/O异常确实会冒泡。

进一步的实验:我添加了一个延迟只是hGetContents调用后:

... 
contents <- hGetContents h 
threadDelay (60 * 1000^2) 
print contents) 

随着这一变化,造成连接,因为,这要归功于懒惰的I/O,没有什么是不会立即引发异常实际上阅读直到print执行。