Haskell:逐行读取文件

mk1*_*k12 5 file-io haskell functional-programming input

我最近做了滑铁卢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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我正在从命令行给定的文件路径中读取,或者从j1.in例如,如果调用此程序j1.hs并将其编译为j1.

我只对文件的前两行有兴趣,所以我已经使用模式匹配来获取这些线路,并将其绑定到kcode在这个例子.然后我读k作一个整数并将它和代码字符串传递给我decode输出的函数.

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

此外,如果有任何代码示例可能更好或更具惯用性,请告诉我.

dav*_*420 8

对文件readFile说:

readFile函数读取文件并以字符串形式返回文件的内容.根据需要,懒惰地读取文件,如同getContents.

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

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

  • 我不同意你的观点,即基本上懒惰的I/O仅在它微不足道时才有用.懒惰I/O的一个非常有用的功能的例子 - 在I/O大量设置中 - 默认情况下数据处理就位,这意味着对大量数据非常有效. (3认同)
  • @amindfv抱歉,我措辞严厉.我的意思是说,当你不断打开(并且只是隐式关闭)大量文件/套接字/其他时,懒惰的I/O是不好的.当一组打开的文件句柄被修复时,它确实很有效 - 当程序没有读取或写入太多不同的文件时没有做太多的I/O. (2认同)

por*_*ges 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
Run Code Online (Sandbox Code Playgroud)

这将确保文件尽快关闭.

但你做的方式很好.