haskell - 在 Haskell 中递归搜索与名称条件匹配的所有文件的目录

标签 haskell filepath file-extension

我在 Haskell 方面比较缺乏经验,我想改进,所以对于我的一个学习项目,我有以下要求:

  • 我想从指定的顶级目录开始搜索,不一定是绝对路径。
  • 我想查找给定扩展名的所有文件,例如 .md .
  • 我不想搜索隐藏目录,比如 toplevel/.excluded .
  • 我希望能够忽略隐藏文件,如 gedit 产生 .filename.md.swp .
  • 作为我的函数的结果,我想得到一个完整的文件列表。

  • 我到处搜索。这是我到目前为止所拥有的:
    import qualified System.FilePath.Find as SFF
    import qualified Filesystem.Path.CurrentOS as FP
    
    srcFolderName = "src"
    outFolderName = "output"
    resFolderName = "res"
    
    ffNotHidden :: SFF.FindClause Bool
    ffNotHidden = SFF.fileName SFF./~? ".?*"
    
    ffIsMD :: SFF.FindClause Bool
    ffIsMD = SFF.extension SFF.==? ".md" SFF.&&? SFF.fileName SFF./~? ".?*"
    
    findMarkdownSources :: FilePath -> IO [FilePath]
    findMarkdownSources filePath = do
        paths <- SFF.find ffNotHidden ffIsMD filePath
        return paths
    

    这行不通。 “findMarkdownSources”中的 printf 样式调试,我可以验证 filePath 是否正确,例如"/home/user/testdata" (打印包括“,以防万一)。列表paths总是空的。我绝对确定我指定的目录中有markdown文件(查找/path/to/dir -name“* .md” 找到它们)。

    因此,我有一些具体的问题。
  • 是否有原因(过滤器不正确),例如,为什么这段代码不应该工作?
  • 在 haskell 中有很多方法可以做到这一点。似乎至少有六个包(fileman、system.directory、system.filepath.find)专用于此。这里有一些问题可以回答这样的问题:
  • Streaming recursive descent of a directory in Haskell
  • Is there some directory walker in Haskell?
  • avoid recursion into specifc folder using filemanip

  • 每个人都有大约三种独特的方式来实现我想要实现的目标,所以,我们几乎有 10 种方式来实现它......
  • 有没有我应该这样做的特定方式?如果是,为什么?如果有帮助,一旦我有了我的文件列表,我将遍历整个文件,打开并解析每个文件。

  • 如果它有帮助,我对基本的 haskell 相当满意,但是如果我们开始对 monad 和应用仿函数太重,你需要放慢速度(我没有使用足够的 haskell 来让这个留在我的脑海中)。不过,我发现有关 hackage 的 haskell 文档难以理解。

    最佳答案

    so, we're nearly at 10 ways to do it...



    这是另一种方法,使用 directory 中的函数。 , filepathextra包,但没有太多的单子(monad)魔法:
    import Control.Monad (foldM)
    import System.Directory (doesDirectoryExist, listDirectory) -- from "directory"
    import System.FilePath ((</>), FilePath) -- from "filepath"
    import Control.Monad.Extra (partitionM) -- from the "extra" package
    
    traverseDir :: (FilePath -> Bool) -> (b -> FilePath -> IO b) -> b -> FilePath -> IO b
    traverseDir validDir transition =
        let go state dirPath =
                do names <- listDirectory dirPath
                   let paths = map (dirPath </>) names
                   (dirPaths, filePaths) <- partitionM doesDirectoryExist paths
                   state' <- foldM transition state filePaths -- process current dir
                   foldM go state' (filter validDir dirPaths) -- process subdirs
         in go
    

    这个想法是用户通过 FilePath -> Bool过滤不需要的目录的功能;也是一个初始状态b和一个转换函数 b -> FilePath -> IO b处理文件名,更新 b状态,可能有一些副作用。请注意,状态的类型是由调用者选择的,调用者可能会将有用的东西放在那里。

    如果我们只想在生成文件名时打印它们,我们可以这样做:
    traverseDir (\_ -> True) (\() path -> print path) () "/tmp/somedir"
    

    我们正在使用 ()作为一个虚拟状态,因为我们在这里并不需要它。

    如果我们想将文件累积到一个列表中,我们可以这样做:
    traverseDir (\_ -> True) (\fs f -> pure (f : fs)) [] "/tmp/somedir" 
    

    如果我们想过滤一些文件怎么办?我们需要调整传递给 traverseDir 的转换函数所以它会忽略它们。

    关于haskell - 在 Haskell 中递归搜索与名称条件匹配的所有文件的目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51712083/

    相关文章:

    PHP:获取文件扩展名不适用于上传到 S3

    列出树中叶子的路径

    c++ - 为什么不按默认构建的路径划分路径只需在 Visual Studio 中添加尾随分隔符?

    rgb - 语义分割的标记图像应该如何?

    Java调用PrinterJob.getPrinterJob().defaultPage()后找不到本地文件

    javascript - JavaScript 中图像的文件路径

    c++ - 计算目录中具有给定扩展名的文件数 - C++?

    list - 将函数 List 写入元组

    haskell - 如何从 xmonad 默认配置中删除 "Full"布局中的边框?

    haskell - 使用选项 -fexternal-interpreter -prof 启动 ghci 时出错