3

在 Reddit 上讨论了一些代码,这让我很好奇这将如何在 io-streams 中实现。考虑以下代码,它遍历目录结构并打印出所有文件名:

import           Control.Exception         (bracket)
import qualified Data.Foldable             as F
import           Data.Streaming.Filesystem (closeDirStream, openDirStream,
                                            readDirStream)
import           System.Environment        (getArgs)
import           System.FilePath           ((</>))

printFiles :: FilePath -> IO ()
printFiles dir = bracket
    (openDirStream dir)
    closeDirStream
    loop
  where
    loop ds = do
        mfp <- readDirStream ds
        F.forM_ mfp $ \fp' -> do
            let fp = dir </> fp'
            ftype <- getFileType fp
            case ftype of
                FTFile -> putStrLn fp
                FTFileSym -> putStrLn fp
                FTDirectory -> printFiles fp
                _ -> return ()
            loop ds

main :: IO ()
main = getArgs >>= mapM_ printFiles

假设我们想要创建某种流文件路径表示,而不是简单地打印文件。我知道这在枚举器、管道和管道中是如何工作的。但是,由于中间步骤需要获取稀缺资源(DirStream),我不确定 io-streams 的实现是什么。有人可以提供一个如何做到这一点的例子吗?

为了比较,这里是管道实现,它是通过bracketP和实现的MonadResource。下面是如何使用管道代码来实现与上面相同的文件打印程序:

import           Control.Monad.IO.Class       (liftIO)
import           Control.Monad.Trans.Resource (runResourceT)
import           Data.Conduit                 (($$))
import           Data.Conduit.Filesystem      (sourceDirectoryDeep)
import qualified Data.Conduit.List            as CL
import           System.Environment           (getArgs)

main :: IO ()
main =
    getArgs >>= runResourceT . mapM_ eachRoot
  where
    -- False means don't traverse dir symlinks
    eachRoot root = sourceDirectoryDeep False root
                 $$ CL.mapM_ (liftIO . putStrLn)
4

1 回答 1

1

典型的风格是做这样的事情:

traverseDirectory :: RawFilePath -> (InputStream RawFilePath -> IO a) -> IO a

即一个标准的“with-”函数,具有明显的实现。

编辑:添加了一个工作示例实现:https ://gist.github.com/gregorycollins/00c51e7e33cf1f9c8cc0

它并不完全复杂,但也不像我最初建议的那样微不足道。

于 2014-05-09T08:54:12.013 回答