2017-05-30 11 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 

のコードは、この再帰的な場合には再帰がありませんでした。

また、小さな生産者とのパイプの組成物にまでこのプロデューサーを破ることができます。私はそれがControl.Monadまたはその代わりに、手動再帰のPipe.Preludeからコンビネータの1からforeverを使用すると便利です見つける

{-# 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) 

。これは、このような小さなタイプミスを減らすのに役立ちます。しかし、子供たちが言うように、あなたの走行距離は非常によく変わるかもしれません。

+0

私は、あなたがしたように問題を解消することは考えていません。非常に素晴らしい。おそらく、これは別のSOの質問の質問ですが、このアプローチでは、深い最初の検索順序で訪問しているので、オープンディレクトリの制限に達する可能性があります。 –

+0

@DamianNadales私はディレクトリがそのように動作するとは思わない。 1つを開いてハンドルを取得せず、その内容をリストするためにカーソルのように使用します。あなたは単にファイルパスを持っていて、システムコールを作成したときにそのパスの内容のリストを与えるシステムコールを作成するだけです。 – Carl

+0

私は、ディレクトリストリームをカーソルとして使用していると思っていました。私はそれを開いていて、その内容を使って繰り返しました: 'readDirStream stream' ... –

関連する問題