简体   繁体   English

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

[英]Detecting I/O exceptions in a lazy String from hGetContents?

hGetContents returns a lazy String object that can be used in purely functional code to read from a file handle. hGetContents返回一个惰性String对象,该对象可用于纯函数代码以从文件句柄中读取。 If an I/O exception occurs while reading this lazy string, the underlying file handle is closed silently and no additional characters are added to the lazy string. 如果在读取此惰性字符串时发生I / O异常,则会以静默方式关闭基础文件句柄,并且不会向延迟字符串添加其他字符。

How can this I/O exception be detected? 如何检测此I / O异常?

As a concrete example, consider the following program: 作为一个具体的例子,考虑以下程序:

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)

If an exception occurs while reading the first line of the file, this program will print the number of characters until the I/O exception occurs. 如果在读取文件的第一行时发生异常,则此程序将打印字符数,直到发生I / O异常。 Instead I want the program to crash with the appropriate I/O exception. 相反,我希望程序崩溃并使用适当的I / O异常。 How could this program be modified to have that behavior? 如何修改此程序以具有该行为?

Edit: Upon closer inspection of the hGetContents implementation, it appears that the I/O exception is not ignored but rather bubbles up through the calling pure functional code to whatever IO code happened to trigger evaluation, which has the opportunity to then handle it. 编辑:仔细检查hGetContents实现后,似乎不会忽略I / O异常,而是通过调用纯函数代码冒泡到任何触发评估的IO代码,然后有机会处理它。 (I was not previously aware that pure functional code could raise exceptions.) Thus this question is a misunderstanding. (我以前没有意识到纯函数代码会引发异常。)因此,这个问题是一个误解。

Aside: It would be best if this exceptional behavior were verified empirically. 旁白:如果通过经验验证这种特殊行为,那将是最好的。 Unfortunately it is difficult to simulate a low level I/O error. 不幸的是,很难模拟低级I / O错误。

Lazy IO is considered to be a pitfall by many haskellers and as such is advised to keep away from. Lazy IO 被认为是许多haskellers 的陷阱 ,因此建议远离。 Your case colorfully describes why. 你的案例多彩地描述了原因。

There is a non-lazy alternative of hGetContents function . 有一个非懒惰的hGetContents函数替代方案 It works on Text , but Text is also a generally preferred alternative to String . 它适用于Text ,但Text也是String首选替代品。 For convenience, there are modern preludes, replacing the String with Text : basic-prelude and classy-prelude . 为方便起见,有现代的前奏,用Text替换String基本前奏经典前奏

Aside: It would be best if this exceptional behavior were verified empirically. 旁白:如果通过经验验证这种特殊行为,那将是最好的。 Unfortunately it is difficult to simulate a low level I/O error. 不幸的是,很难模拟低级I / O错误。

I was wondering about the same thing, found this old question, and decided to perform an experiment. 我想知道同样的事情,找到了这个老问题,并决定进行一项实验。

I ran this little program in Windows, that listens for a connection and reads from it lazily: 我在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)

From a Linux machine, I opened a connection using nc : 在Linux机器上,我使用nc打开了一个连接:

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

And then used Windows Sysinternal's TCPView utility to forcibly close the connection. 然后使用Windows Sysinternal的TCPView实用程序强制关闭连接。 The result was: 结果是:

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

It appears that I/O exceptions do bubble up. 似乎I / O异常确实冒泡了。

A further experiment: I added a delay just after the hGetContents call: 进一步的实验:我在hGetContents调用之后添加了一个延迟:

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

With this change, killing the connection doesn't immediately raise an exception because, thanks to lazy I/O, nothing is actually read until print executes. 通过此更改,终止连接不会立即引发异常,因为由于惰性I / O,在执行print之前实际上不会读取任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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