您将如何遍历目录并对所有文件执行某些功能并以内存有效的方式组合输出?
How would you traverse a directory and do some function on all files and combine the output in a memory efficient manner?
设置
我需要遍历超过 100 个 .txt 文件的目录,打开每个文件并对每个文件执行一些函数,然后合并结果。这些文件很大,大约有 10GB。伪代码中的一些常见操作可能是:
foldr concatFile mempty $ openFile <$> [filePath1, ..., filePathn]
foldr countStuff 0 $ openFile <$> [filePath1, ..., filePathn]
诀窍是确保所有文件永远不会同时存在于内存中,我以前天真的解决方案在我的 mac 上创建了各种交换文件。
此外,如果 filePath 之一无效,我想跳过
它并继续执行该程序。
我的解决方案
目前我正在使用 conduit,如果可能的话,我想找到一个使用 conduit 的解决方案。但如果它不是正确的工具,我也可以使用其他工具。
您可以像这样嵌套管道执行:
{-# 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)
将 processFile
替换为你想做的任何事情——包括
忽略该文件。我的理解是 sourceFile
Producer 会有效地分块
文件的内容。
而且,根据 this Yesod article,sourceDirectoryDeep
应该
高效地遍历目录结构。
你显然不能用 sourceDirectoryDeep
做的事情是修剪
目录。
设置
我需要遍历超过 100 个 .txt 文件的目录,打开每个文件并对每个文件执行一些函数,然后合并结果。这些文件很大,大约有 10GB。伪代码中的一些常见操作可能是:
foldr concatFile mempty $ openFile <$> [filePath1, ..., filePathn]
foldr countStuff 0 $ openFile <$> [filePath1, ..., filePathn]
诀窍是确保所有文件永远不会同时存在于内存中,我以前天真的解决方案在我的 mac 上创建了各种交换文件。 此外,如果 filePath 之一无效,我想跳过 它并继续执行该程序。
我的解决方案
目前我正在使用 conduit,如果可能的话,我想找到一个使用 conduit 的解决方案。但如果它不是正确的工具,我也可以使用其他工具。
您可以像这样嵌套管道执行:
{-# 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)
将 processFile
替换为你想做的任何事情——包括
忽略该文件。我的理解是 sourceFile
Producer 会有效地分块
文件的内容。
而且,根据 this Yesod article,sourceDirectoryDeep
应该
高效地遍历目录结构。
你显然不能用 sourceDirectoryDeep
做的事情是修剪
目录。