Haskell:逐行读取文件

时间:2012-03-02 00:58:19

标签: haskell file-io input functional-programming

我最近做了Waterloo CCC,我觉得Haskell是回答这些类型问题的完美语言。我还在学习它。不过,我在输入方面有点挣扎。

以下是我正在使用的内容:

import IO
import System.Environment
import System.FilePath

…

main = do
    name <- getProgName
    args <- getArgs
    input <- readFile $
        if not (null args)
            then head args
            else dropExtension name ++ ".in"
    let (k:code:_) = lines input
    putStrLn $ decode (read k) code

如您所见,我正在从命令行给定文件路径或从j1.in读取,例如,如果此程序被调用j1.hs并编译为j1。< / p>

我只对文件的前两行感兴趣,所以我使用模式匹配来获取这些行并将它们绑定到kcode,在本例中。然后我将k读作整数并将其传递给我的decode函数,并将其输出。

我想知道readFile是否正在将整个文件加载到内存中,这很糟糕。但后来我开始思考,也许是因为Haskell是懒惰的,它只会读取前两行,因为这是后来要求的全部内容。我是对的吗?

此外,如果该代码示例中有任何内容可能更好或更具惯用性,请告知我们。

4 个答案:

答案 0 :(得分:8)

documentation for readFile说:

  

readFile函数读取文件并以字符串形式返回文件内容。与getContents一样,该文件可以按需延迟读取。

所以是的,它只会读取文件的前两行(缓冲意味着它可能会在幕后阅读更多)。但这是readFile的属性,而不是所有Haskell I / O函数。

对于I / O繁重的程序(例如Web服务器)来说,懒惰的I / O是一个坏主意,但它对于没有做太多I / O的简单程序很有效。

答案 1 :(得分:7)

是的,readFile是懒惰的。如果你想明确它,你可以使用:

import Control.Monad (replicateM)
import System.IO

readLines n f = withFile f ReadMode $ replicateM n . hGetLine

-- in main
    (k:code:_) <- readLines 2 filename

这将确保文件尽快关闭。

但你做得好的方式很好。

答案 2 :(得分:3)

readFile懒惰地读取文件,因此除非您使用整个文件,否则它不会将整个文件读入内存。它通常不会完全读取前两行,因为它读取块,但它只会读取所需数量的块来查找第二个换行符。

答案 3 :(得分:2)

Haskell中的I / O通常不是懒惰的。但是,具体readFile函数是懒惰的。

其他人也说了同样的话。我还没有看到任何人指出的是,在程序结束或垃圾收集器运行之前,您打开的文件将不会关闭。这只意味着OS文件句柄可能会保持打开时间超过必要的时间。在你的程序中,这可能没什么大不了的。但在一个更复杂的项目中,它可能是。