如何列出当前目录下的所有文件

14

我想要编写一个Haskell函数,以返回当前目录下的文件,例如:

将当前目录更改为:

 :cd c:/code/haskell

然后编写一个函数,该函数以集合形式返回文件,例如:

 [x | x <-getDirectoryContents ]

已编辑:

我编写了一个类似于这样的函数,用于列出文件 (参考:http://zvon.org/other/haskell/Outputdirectory/index.html)。

import Directory 

main = _dir "/tmp/FOO"

_dir _path =do
    setCurrentDirectory _path
    _cd <- getCurrentDirectory
    print _cd
    _file <- getDirectoryContents _cd
    print _file

所以调用_dir "c:/code/haskell"将列出所有文件+目录名称(非递归)。现在我想在谓词函数中调用它,例如:

[ x| x <- _dir  "c:/code/haskell" | x start with 'haskell_' ]  

我想要在文件名上应用一个过滤器


你需要改变当前目录吗?getDirectoryContents函数需要一个目录作为参数。 - stusmith
我需要一个函数来列出给定目录中的所有文件,并在SET PREDICATE中调用它,并应用一些过滤器,以仅列出满足某些条件的名称。谢谢。 - sakhunzai
11
那些下划线太丑了... - alternative
4
更重要的是,“underscore”通常意味着“丢弃”,所以我(以及我相信大多数Haskeller)将它们视为未使用的变量。 - stusmith
6
GHC也是这样对待它们的。选项-fwarn-unused-matches会忽略以下划线开头的名称。 - hammar
1
@hammar - 啊,我没意识到所有以下划线开头的名称都是这样。我以为只有一个下划线表示未使用的匹配。每天都会学到新东西... - stusmith
6个回答

24

[x |x <- getDirectoryContents :: FilePath -> IO [FilePath]] 返回以下错误:无法匹配预期类型 [t0]' 和实际类型 FilePath -> IO [FilePath]' ... 我是 Haskell 的初学者,请多多关照。 - sakhunzai
@sakhunzai:在GHCi提示符下尝试getDirectoryContents“。”。如果可以工作,那么学习有关IO单子的知识。 - Fred Foo
我发布的是一个函数签名 :)..不幸的是,我在这个系统上没有Haskell..我希望来自伟大的Haskell社区的某个人能够给你精确的代码。 - Ankur
2
只想补充一点..在 Haskell 中,它不会像你使用过的其他编程语言那样。其中涉及到不同的概念,因此建议您在学习 Haskell 时先学习这些概念,然后再尝试编写代码,否则您可能会感到困惑。一个很好的起步书籍是:http://learnyouahaskell.com/ - Ankur
感谢Ankur和larsmans,我现在有这样的代码:import Directory main = _dir "/tmp/FOO" _dir _path = do setCurrentDirectory _path _cd <- getCurrentDirectory print _cd _file <- getDirectoryContents _cd print _file - sakhunzai

12

以下方案如何:

import Data.List
import System.Directory

main = do all <- getDirectoryContents "/tmp/FOO"
          let filtered = filter (isPrefixOf "haskell") all
          print filtered

liftM 常常能够很好地整理代码(在我看来):print =<< liftM (filter (isPrefixOf "haskell")) (getDirectoryContents ".") (编辑:但是,stusmith 的代码更简单易懂,适合初学者) - Thomas M. DuBuisson
几乎完成了!getFiles :: String -> String -> IO () getFiles dp flt = do files <- getDirectoryContents dp; let filtered = filter (isPrefixOf flt) files print filtered 我不明白为什么每个人都让我直接将文件名打印到控制台。是否有可能将文件名作为字符串进行转换并将其存储到变量中,然后使用除PRINT之外的某些函数输出它。我的理解是,print直接将文件名作为字符串数组回显到控制台。谢谢。 - sakhunzai

8
你只需要编写一个函数,它能够返回当前目录中的所有文件。具体做法如下:
import System.Directory

filesInCurDir = getCurrentDirectory >>= getDirectoryContents

>>= 运算符是具有值传递的单子序列运算符。最好在这里描述:http://www.haskell.org/tutorial/monads.html

如果您要在ghci中使用此功能:

let filesInCurDir = getCurrentDirectory >>= getDirectoryContents

您可以检查该函数的类型为filesInCurDir :: IO [FilePath],因此保持了“单子性质”。

因此,如果您想进一步过滤文件,可以执行以下操作:

let filteredFilesInCurDir = 
    getCurrentDirectory >>= 
    getDirectoryContents >>= 
    \files -> return [ x | x <- files, (length x) > 10 ]

如果您想每次都通过过滤器:

let filterFilesInCurDir f = 
    getCurrentDirectory >>= 
    getDirectoryContents >>= 
    \files -> return [ x | x <- files, f x ]

这与以下表达式相同:

let filteredFilesInCurDir f = 
    getCurrentDirectory >>= 
    getDirectoryContents >>= 
    return . filter f

你可以像这样使用它:

filterFilesInCurDir (\x -> (length x) > 2)

5
第一点:表达式[x | x <- lst]lst完全相同,因此如果lst是一个列表,则不需要使用列表推导式。
第二点:要使[x | x <-getDirectoryContents ]起作用,值getDirectoryContents应为一个列表。但事实并非如此!getDirectoryContents是一个IO值。
您可以以下面的方式使用此函数(在单子表达式中):
do 
  files <- getDirectoryContents "."
  print files

(或者 - 在 ghci 中使用:do; files <- getDirectoryContents "."; print files

files 的类型为 [FilePath],而 while 表达式的类型为 IO ()


谢谢phyinfo,这比我的好(请看我的编辑)。我们能否在谓词中编写一个过滤器,以便对名称进行筛选。再次感谢您的帮助。 - sakhunzai
在我看来,更清晰的写法是 getDirectoryContents "." >>= print - alternative
1
@sakhunzai:如果你想使用谓词“pred”过滤文件,则可以执行以下操作:do; files <- getDirectoryContents; print $ filter pred files - phynfo
更美观的输出是 mapM_ print files - alternative

5

filemanip包为特定任务提供了更广泛和灵活的功能。

例如,列出给定目录中的常规文件。

> :m + System.FilePath.Find
> :t find always (fileType ==? RegularFile)
find always (fileType ==? RegularFile) :: FilePath -> IO [FilePath]

这个软件包兼容Windows(因为它依赖于unix-compat而不是仅仅依赖于unix),并且还拥有整洁的自我描述文档。


filemanip 提供了一种快速列出目录的方法(例如通过定义递归谓词和/或惰性列表) - Joe

2
这里提供另一种使用 Control.Applicative 的方法:

import Control.Applicative
import System.Directory

isRegularFileOrDirectory :: FilePath -> Bool
isRegularFileOrDirectory f = f /= "." && f /= ".."

main :: IO ()
main = do
  fileNames <- filter isRegularFileOrDirectory <$> getDirectoryContents "."
  putStrLn $ show $ fileNames

太好了,谢谢。它给了我以下内容:getDirectoryContents "../" [".","..",".DS_Store","Clojure","Haskell","Java","Mobile","nll","Phing"] - sakhunzai
@sakhunzai:不用谢。显然,您可以使用自己选择的谓词替换isRegularFileOrDirectory - Richard Cook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接