Haskell中的“资源忙(文件被锁定)”错误

时间:2011-02-19 19:52:12

标签: haskell

我对Haskell很新。事实上,我正在研究this section of this tutorial. 我偶然发现了这段代码:

import System.IO     
import Data.Char  

main = do     
    contents <- readFile "girlfriend.txt"     
    writeFile "girlfriendcaps.txt" (map toUpper contents) 

其中读取名为“girlfriend.txt”的文件内容,并将文件的大写版本写入名为“girlfriendcaps.txt”的新文件。

所以,我想稍微修改代码以获取要处理的文件的名称。我将代码更改为:

import System.IO
import Data.Char

main = do
    path <- getLine
    contents <- readFile path
    writeFile path (map toUpper contents)

现在,显然这里的主要区别在于我正在读取和写入同一个文件。正如我现在想的那样,这肯定是一个懒惰的评估,但我得到了“资源忙”的错误信息。如果我错了,请纠正我,但我想readFile不会开始读取文件,直到writeFile要求它的内容。然后writeFile尝试写入文件,但它仍然必须打开文件,因为它也要求内容。我在那附近吗?

所以,真正的问题是:如何在Haskell中读取和写入相同的文件?这是有道理的,因为你会更频繁地从你读取的文件写入不同的文件,但是对于我自己的启发,你会如何读写同一个文件?

3 个答案:

答案 0 :(得分:25)

确实,这是一个“懒惰的评价事物”。

import System.IO
import Data.Char

main = do
    path <- getLine
    contents <- readFile path
    writeFile path (map toUpper contents)

请记住,Haskell在评估中主要是懒惰的,IO子系统也是如此。因此,当您调用'readFile'时,您开始从文件中传输数据。然后,当您立即调用“writeFile”时,您开始将字节流回到同一个文件

这将是一个错误(即破坏您的数据),因此Haskell会锁定资源,直到它被完全评估,并且您收到一条很好的错误消息。

有两种解决方案:

  • 不要破坏性地覆盖文件,而是复制到新文件
  • 或者,使用严格的IO

要使用严格的IO,建议使用'text'或'strict'包。

答案 1 :(得分:9)

您正在寻找的是如何在ReadWriteMode中打开文件。

fileHandle <- openFile "fileName.txt" ReadWriteMode
contents <- hGetContents fileHandle

在文件中向前和向后导航有一些棘手的东西。

请参阅RWH的Working with files and handles和System.IO文档中的Operations on Handles

答案 2 :(得分:6)

取决于你想要做什么。作为一项规则,在任何语言中,这可能是一个糟糕的设计,因为如果在程序内部或外部出现任何问题(例如用户错误),那么您已经销毁了原始数据并且无法再次尝试。它还要求将整个文件保存在内存中,如果它只有几个字节就很酷,但是当某人决定在一个非常大的文件上运行它时就不那么好了。

如果你真的想这样做,那么为输出生成一个临时文件名,然后一旦你知道你已成功写入它,你可以删除原文并重命名新文件。