2017-05-30 37 views
2

我读完Pipes tutorial,我想编写一个函数以递归方式列出目录中的所有文件。我试着用下面的代码:递归地列出目录下的所有文件,使用管道

enumFiles :: FilePath -> Producer' FilePath (PS.SafeT IO)() 
enumFiles path = 
    PS.bracket (openDirStream path) (closeDirStream) loop 
    where 
    loop :: DirStream -> Producer' FilePath (PS.SafeT IO)() 
    loop ds = PS.liftBase (readDirStream ds) >>= checkName 
     where 
     checkName :: FilePath -> Producer' FilePath (PS.SafeT IO)() 
     checkName "" = return() 
     checkName "." = loop ds 
     checkName ".." = loop ds 
     checkName name = PS.liftBase (getSymbolicLinkStatus newPath) 
         >>= checkStat newPath 
      where newPath = path </> name 

     checkStat path stat 
      | isRegularFile stat = yield path >> loop ds 
      | isDirectory stat = enumFiles path 
      | otherwise = loop ds 

然而,这生产者将尽快达到return()终止。我想我不是以正确的方式撰写它的,但我没有看到做这件事的正确方法。

回答

3

只需改变这一行:

| isDirectory stat = enumFiles path 

| isDirectory stat = enumFiles path >> loop ds 

的代码是缺少这个递归情况下,递归。

您也可以达到打破这种生产成更小的生产商和管道组成:

{-# LANGUAGE RankNTypes #-} 

module Main where 

import qualified Pipes.Prelude as P 
import qualified Pipes.Safe as PS 

import   Control.Monad 
import   Pipes 
import   System.FilePath.Posix 
import   System.Posix.Directory 
import   System.Posix.Files 

readDirStream' :: FilePath -> Producer' FilePath (PS.SafeT IO)() 
readDirStream' dirpath = 
    PS.bracket (openDirStream dirpath) closeDirStream (forever . loop) 
    where 
    loop stream = 
     liftIO (readDirStream stream) >>= yield 

enumFiles :: FilePath -> Producer' FilePath (PS.SafeT IO)() 
enumFiles path = 
    readDirStream' path 
    >-> P.takeWhile (/= "") 
    >-> P.filter (not . flip elem [".", ".."]) 
    >-> P.map (path </>) 
    >-> forever (do 
        entry <- await 
        status <- liftIO $ getSymbolicLinkStatus entry 
        when (isDirectory status) (enumFiles entry) 
        when (isRegularFile status) (yield entry)) 

main :: IO() 
main = 
    PS.runSafeT $ runEffect (enumFiles "/tmp" >-> P.stdoutLn) 

我觉得它往往有助于使用foreverControl.Monad或从Pipe.Prelude代替人工递归组合子之一;它有助于减少像这样的小错别字。然而,正如孩子们所说,你的里程可能会有很大的不同。

+0

我还没有想过如你所做的那样解构问题。非常好。可能这是另一个SO问题的一个问题,但是通过这种方法,我们可能会达到开放目录的限制,因为我们正在深入探索它们的搜索顺序,对吧? –

+0

@DamianNadales我不认为目录是这样工作的。你不打开一个并获得一个句柄,并使用它像一个光标来列出它的内容。您只需要一个文件路径并创建一个系统调用,该系统调用可以在系统调用完成时为您提供该路径的内容列表。 – Carl

+0

我以为我使用目录流作为游标,因为我正在打开它,并使用'readDirStream stream'遍历其内容... –

相关问题