我想知道是否有一种简单的方法可以一次从文件中获取一行,而不会最终将整个文件加载到内存中。我想用 attoparsec 解析器对这些行进行折叠。我尝试将Data.Text.Lazy.IO
与hGetLine
一起使用,这让我记忆深刻。我后来读到最终会加载整个文件。
我还尝试将 pipes-text 与folds
和view lines
一起使用:
s <- Pipes.sum $
folds (\i _ -> (i+1)) 0 id (view Text.lines (Text.fromHandle handle))
print s
只计算行数,它似乎做了一些不稳定的东西&#34; hGetChunk:无效的参数(无效的字节序列)&#34; wc -l
需要1分钟,需要11分钟。我听说 pipes-text 可能会遇到一些巨大的问题? (每行大约1GB)
我真的愿意接受任何建议,除了新手readLine
之外,找不到多少搜索。
谢谢!
答案 0 :(得分:7)
以下代码使用Conduit,并将:
lineC
组合器yield
值1
并丢弃行内容,而无需立即将整行读入内存1
s屈服并打印您可以将yield 1
代码替换为将在各行上处理的内容。
#!/usr/bin/env stack
-- stack --resolver lts-8.4 --install-ghc runghc --package conduit-combinators
import Conduit
main :: IO ()
main = (runConduit
$ stdinC
.| decodeUtf8C
.| peekForeverE (lineC (yield (1 :: Int)))
.| sumC) >>= print
答案 1 :(得分:3)
这可能是解码文本流的最简单
{-#LANGUAGE BangPatterns #-}
import Pipes
import qualified Pipes.Prelude as P
import qualified Pipes.ByteString as PB
import qualified Pipes.Text.Encoding as PT
import qualified Control.Foldl as L
import qualified Control.Foldl.Text as LT
main = do
n <- L.purely P.fold (LT.count '\n') $ void $ PT.decodeUtf8 PB.stdin
print n
对于我生成的文件,它只需要大约14%的wc -l
,这只是逗号和数字的长行。正如文档所述,IO应该使用Pipes.ByteString
正确完成,其余的是各种各样的便利。
你可以在每行上映射一个attoparsec解析器,由view lines
区分,但请记住,attoparsec解析器可以随意累积整个文本,这对于1 GB的块可能不是一个好主意的文字。如果每行上都有重复的数字(例如,单词分隔数字),您可以使用Pipes.Attoparsec.parsed
来传输它们。