本文介绍了是什么引起了这个“关闭句柄延迟阅读”错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚从最新的资源中安装了GHC,现在我的程序给了我一个关于关闭句柄延迟读取的错误消息。这是什么意思?

I just installed GHC from the latest sources, and now my program gives me an error message about a "delayed read on closed handle". What does this mean?

推荐答案

基本的懒惰I / O原语 hGetContents ,产生一个字符串懒惰 - 它只会根据需要从句柄读取,以产生程序实际需要的字符串部分。但是,一旦句柄关闭,就不再可能从句柄中读取数据,并且如果您尝试检查尚未读取的字符串的一部分,则会发生此异常。例如,假设你写了

The fundamental lazy I/O primitive, hGetContents, produces a String lazily—it only reads from the handle as needed to produce the parts of the string your program actually demands. Once the handle has been closed, however, it is no longer possible to read from the handle, and if you try to inspect a part of the string that was not yet read, you will get this exception. For example, suppose you write

main = do
  most <- withFile "myfile" ReadMode
                (\h -> do
                         s <- hGetContents h
                         let (first12,rest) = splitAt 12 s
                         print first12
                         return rest)
  putStrLn most

GHC打开 myfile 并将其设置为懒读入我们绑定的字符串 s 。它不会实际上开始从文件读取。然后它设置一个懒惰的计算来分割12个字符后的字符串。然后 print 强制执行计算,GHC读入长度至少为12个字符的 myfile 块,并打印出前十二。然后在 withFile 完成时关闭文件,并尝试打印剩下的文件。如果文件比缓存的块GHC长,那么一旦到达块的末尾,就会得到延迟读取异常。

GHC opens myfile and sets it up for lazy reading into the string we've bound to s. It does not actually begin reading from the file. Then it sets up a lazy computation to split the string after 12 characters. Then print forces that computation, and GHC reads in a chunk of myfile at least 12 characters long, and prints out the first twelve. It then closes the file when withFile completes, and attempts to print out the rest. If the file was longer than the chunk GHC buffered, you will get the delayed read exception once it reaches the end of the chunk.

您需要确定您已经在关闭文件或从 withFile 返回之前实际阅读了您需要的所有内容C $ C>。如果你传给 withFile 的函数只是做了一些IO并返回一个常量(比如()),不必担心这一点。如果你需要通过懒读来产生一个真正的价值,你需要确保在返回之前充分地强制这个值。在上面的示例中,可以使用 Control.DeepSeq 模块中的函数或运算符将字符串强制为正常形式:

You need to be sure that you've actually read everything you need before closing the file or returning from withFile. If the function you pass to withFile just does some IO and returns a constant (such as ()), you don't need to worry about this. If you need to it to produce a real value from a lazy read, you need to be sure to force that value sufficiently before returning. In the example above, you can force the string to "normal form" using a function or operator from the Control.DeepSeq module:

return $!! rest

这确保字符串的其余部分在 withFile 关闭文件。 $ !! 方法如果返回的是从文件内容计算出的某个值,只要它是 NFData的实例类。在这种情况下,还有其他许多情况,最好将处理文件内容的其余代码移动到传递给 withFile 的函数中,如下所示:

This ensures that the rest of the string is actually read before withFile closes the file. The $!! approach also works perfectly well if what you return is some value calculated from the file contents, as long as it's an instance of the NFData class. In this case, and many others, it's even better to simply move the rest of the code for processing the file contents into the function passed to withFile, like this:

main = withFile "myfile" ReadMode
            (\h -> do
                     s <- hGetContents h
                     let (first12,rest) = splitAt 12 s
                     print first12
                     putStrLn rest)

另一个需要考虑的函数是 readFile 。 readFile 保持文件处于打开状态,直到读完文件。然而,如果你知道你真的需要文件的全部内容,那么你应该只使用 readFile ,否则你可能会泄漏文件描述符。

Another function to consider, as an alternative, is readFile. readFile holds the file open until it has finished reading the file. You should only use readFile, however, if you know that you will actually demand the entire contents of the file—otherwise you could leak file descriptors.

根据Haskell报告,一旦句柄关闭,字符串的内容就会变成固定的。

According to the Haskell Report, once the handle is closed, the contents of the string become fixed.

过去,GHC只是在句柄关闭时缓冲结束时结束字符串。例如,如果在关闭句柄之前检查了字符串的前10个字符,并且GHC已经缓冲了另外634个字符,但没有到达文件末尾,那么您将得到一个包含644个字符的普通字符串。这是新用户混淆的常见原因,也是生产代码中偶然出现的错误。

In the past, GHC has simply ended the string at the end of whatever was buffered at the time the handle was closed. For example, if you had inspected the first 10 characters of the string before you closed the handle, and GHC had buffered an additional 634 characters, but not reached the end of the file, then you would get a normal string with 644 characters. This was a common source of confusion among new users and an occasional source of bugs in production code.

从GHC 7.10.1开始,这种行为正在发生变化。当你关闭一个懒惰地读取的句柄时,它现在会有效地在缓冲区的末尾放置一个异常,而不是通常的:。因此,如果您尝试检查超出文件关闭点的字符串,您将收到错误消息。

As of GHC 7.10.1, this behavior is changing. When you close a handle that you are reading from lazily, it now effectively puts an exception at the end of the buffer instead of the usual :"". So if you attempt to inspect the string beyond the point where the file was closed, you will get an error message.

这篇关于是什么引起了这个“关闭句柄延迟阅读”错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-24 20:21