你将如何遍历目录并对所有文件执行某些功能并以高效的内存方式组合输出?

chi*_*ro2 6 haskell conduit haskell-pipes

设置

我需要遍历超过100个.txt文件的目录,打开每个文件并对每个文件执行一些功能,然后合并结果.这些文件很大,大约10GB.伪造的代码中的一些常见操作可能是:

foldr concatFile mempty $ openFile <$> [filePath1, ..., filePathn]
foldr countStuff 0      $ openFile <$> [filePath1, ..., filePathn]
Run Code Online (Sandbox Code Playgroud)

诀窍是确保所有文件同时存在于内存中,我以前的天真解决方案在我的mac上创建了各种交换文件.另外,如果其中一个filePath无效,我想跳过它继续该程序.

我的解决方案

目前我正在使用管道,并希望尽可能找到使用管道的解决方案.但如果它不是正确的工具我可以使用别的东西.

Eri*_*ikR 4

您可以像这样嵌套管道执行:

{-# LANGUAGE OverloadedStrings #-}

import Conduit
import qualified Data.ByteString as BS

-- Process a single file
processFile :: FilePath -> IO ()
processFile path = runResourceT (sourceFile path =$= mapC BS.length $$ sumC) >>= print

-- Run processFile for directory in a tree    
doit :: FilePath -> IO ()
doit top = runResourceT $ sourceDirectoryDeep False top $$ mapM_C (liftIO . processFile)
Run Code Online (Sandbox Code Playgroud)

替换processFile为您想要执行的任何操作 - 包括忽略该文件。我的理解是,sourceFile生产者将有效地对文件的内容进行分块。

并且,根据Yesod 文章sourceDirectoryDeep应该有效地遍历目录结构。

您显然无法做的事情sourceDirectoryDeep是修剪目录。

  • @dfeuer 管道(或管道)“foldM”比“Control.Monad.foldM”*不复杂一点。使用从目录遍历懒惰地开发的文件路径列表可能会发生数量惊人的灾难,这是流 io 的原始海报之一。它*只是不简单*并且不应该被推荐。`import Conduit` 比 `import Control.Monad` 短,一旦你输入它,你就拥有了目录树和正确的折叠函数来应用它。 (2认同)