[英]Detecting I/O exceptions in a lazy String from hGetContents?
hGetContents返回一个惰性String对象,该对象可用于纯函数代码以从文件句柄中读取。 如果在读取此惰性字符串时发生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错误。
Lazy IO 被认为是许多haskellers 的陷阱 ,因此建议远离。 你的案例多彩地描述了原因。
有一个非懒惰的hGetContents
函数替代方案 。 它适用于Text
,但Text
也是String
首选替代品。 为方便起见,有现代的前奏,用Text
替换String
: 基本前奏和经典前奏 。
旁白:如果通过经验验证这种特殊行为,那将是最好的。 不幸的是,很难模拟低级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
之前实际上不会读取任何内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.