繁体   English   中英

从hGetContents中检测惰性字符串中的I / O异常?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM