提问人:halloleo 提问时间:7/2/2022 最后编辑:Sridhar Ratnakumarhalloleo 更新时间:7/4/2022 访问量:499
Haskell 的“readFile”是否将整个文件内容读入内存?
Does Haskell's `readFile` read the whole file content into memory?
问:
我想从 Haskell 程序中的大文本文件(~10GB)中选择倒数第一行。n
我找到了一种如何从内部字符串中获取 -th last 的方法:n
myLen = 7
n = 3 -- one-based from the end
myLines = lines myText
idx = myLen - n
theLine = head (drop idx myLines)
main :: IO ()
main = do
putStrLn theLine
关于该函数的文档说它“懒惰地读取内容”,所以一旦到达最后一行,它会将之前的所有行都存储在内存中吗(然后爆炸,因为我没有那么多内存)?readFile
readFile
n
那么,这里是正确的方法吗?另外,如何将“以懒惰的方式”的输出放入行列表中,以便我可以选择最后一行?readFile
IO String
readFile
n
答:
该问题分为几个部分:
关于 readFile 函数的文档说它“懒惰地读取内容”,所以一旦 readFile 到达倒数第 n 行,它是否会将之前的所有行存储在内存中(然后爆炸,因为我没有那么多内存)?
不一定。如果仅循环访问内容并生成结果,则垃圾回收器应解除分配内容。
那么,readFile是正确的方法吗?
我固执己见的回答是,如果它是一个严肃的工具,这不是正确的方法,因为“懒惰 IO”是一罐蠕虫。readFile
如果是快速而肮脏的脚本,那就继续吧,但如果不是,如果性能很重要,那么最好使用较低级别的调用来读取严格的 s,对于你的问题,直接从文件末尾读取并处理它。ByteString
评论
以下程序所需的内存仅与正在读取的文件中最长行的内存一样多:n
-- like drop, but takes its number encoded as a lazy
-- unary number via the length of the first list
dropUnary :: [a] -> [b] -> [b]
dropUnary [] bs = bs
dropUnary (_:as) (_:bs) = dropUnary as bs
takeLast :: Int -> [a] -> [a]
takeLast n as = dropUnary (drop n as) as
main :: IO ()
main = putStrLn . head . takeLast 3 . lines =<< readFile
前奏曲的功能已经很懒惰了,但在这里写了一些小心翼翼的东西。您可以将其视为在文件的“一次传递”中操作,查看连续 n 行的后续块,直到找到最后一个块。由于它不维护对当前正在查看的区块之前的文件内容的任何引用,因此可以对当前区块之前的所有文件内容进行垃圾回收(通常很快就会进行垃圾回收)。lines
takeLast
评论
dropUnary
评论
hSeek
readFile
head (drop 10 xs)
head (drop (length xs - 4) xs
drop (length xs - 4) xs