我对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中读取和写入相同的文件?这是有道理的,因为你会更频繁地从你读取的文件写入不同的文件,但是对于我自己的启发,你会如何读写同一个文件?
答案 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,建议使用'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)
取决于你想要做什么。作为一项规则,在任何语言中,这可能是一个糟糕的设计,因为如果在程序内部或外部出现任何问题(例如用户错误),那么您已经销毁了原始数据并且无法再次尝试。它还要求将整个文件保存在内存中,如果它只有几个字节就很酷,但是当某人决定在一个非常大的文件上运行它时就不那么好了。
如果你真的想这样做,那么为输出生成一个临时文件名,然后一旦你知道你已成功写入它,你可以删除原文并重命名新文件。