2009-09-10 60 views
22

我使用OpenMCL达尔文,我想这样做:如何遍历Common Lisp中的目录?

(loop for f in (directory "somedir") 
    collect (some-per-file-processing f)) 

但我不能让directory返回以外的任何其他NIL,我似乎无法找到任何网上很好的解释(除“每个系统的不同之外”)。

任何指针?

回答

16

您的路径名规范是否包含通配符? Common Lisp中的路径名的东西是有点难以把握在第一 - 至少对我来说是......正如CLHS状态上directory功能:

如果pathspec不是野外, 结果列表将包含两种 零个或一个元素。

为了让您的路径包括通配符,你可以尝试化妆路径功能,如

(directory (make-pathname :directory '(:absolute "srv" "hunchentoot") :name :wild :type "lisp")) 

甚至

(directory (make-pathname :directory '(:absolute "srv" "hunchentoot") :name :wild :type :wild)) 

我发现CL-FAD库有很大的帮助用于处理路径名和文件系统。特别是,其功能list-directory可能比普通标准directory功能更易于使用。

+2

是的工作对我来说 - (目录 “路径”)返回NIL,其中(目录“路径名/*.*”)给了我预期的结果。 – Justicle 2009-09-10 07:14:12

+1

您只需要名称中包含点的文件? – Svante 2009-09-10 07:16:03

+0

怪怪的?我实际上是在.h和.cpp文件之后,但“路径名/ *”返回NIL。 – Justicle 2009-09-10 07:28:42

26

基本上有两种方式来指定路径名:

  • 使用字符串

字符串显然取决于平台:Unix的语法与Windows的语法例子。

"/Users/foo/bar.text" is a valid pathname 
"/Users/foo/*/foo.*" is a valid pathname with two wildcards 

您可以从字符串创建路径对象:

? (pathname "/Users/bar/foo.text") 
#P"/Users/bar/foo.text" 

的#P上述保证路径名对象(而不是字符串)创建,当你读了回去。

? #P"/Users/bar/foo.text" 
#P"/Users/bar/foo.text" 

因此,内部Common Lisp与路径名对象一起工作,但它允许您使用普通字符串,并根据需要为它们生成路径名对象。

当Common Lisp发现没有指定所有组件的路径名称(例如该目录缺失)时,它会从路径名对象填充组件,该对象是variabel * DEFAULT-PATHNAME-DEFAULTS *的值。

使用功能描述你可以看看路径名称(这里Clozure CL)的组成部分:

? (describe (pathname "/Users/bar/*.text")) 
#P"/Users/bar/*.text" 
Type: PATHNAME 
Class: #<BUILT-IN-CLASS PATHNAME> 
TYPE: (PATHNAME . #<CCL::CLASS-WRAPPER PATHNAME #x3000401D03BD>) 
%PATHNAME-DIRECTORY: (:ABSOLUTE "Users" "bar") 
%PATHNAME-NAME: :WILD 
%PATHNAME-TYPE: "text" 
%PHYSICAL-PATHNAME-VERSION: :NEWEST 
%PHYSICAL-PATHNAME-DEVICE: NIL 
  • 使用Lisp函数创建路径对象

MAKE-PATHNAME是函数,它需要几个关键字参数来指定组件。

有时它也是创建基于现有的一个新的路径有用:

(make-pathname :name "foo" :defaults (pathname "/Users/bar/baz.text")) 

如果您使用目录它使用一个带有通配符路径是非常有用的。 DIRECTORY然后将返回匹配路径名的列表。名称'DIRECTORY'有点误导,因为DIRECTORY没有列出目录的内容,但列出了通常使用通配符的路径名的匹配路径名。通配符可以匹配组件中的一系列字符,如/foo/s*c/list*.l*“。还有一个通配符**,用于匹配/ foo/**目录等级的部分/test.lisp,其中的所有文件相匹配test.lisp目录foo和其子目录下。

(directory "/Users/foo/Lisp/**/*.lisp") 

以上应返回“/用户/富/ Lisp语言/”和所有的一切“口齿不清”的文件列表其子目录

要在单一目录使用返回.c文件:

(directory "/Users/foo/c/src/*.c") 

注意这种可怕CTORY返回一个路径名对象列表(不是一个字符串列表)。

? (directory (make-pathname 
       :name "md5" 
       :type :wild 
       :directory '(:absolute "Lisp" "cl-http" "cl-http-342" "server"))) 
(#P"/Lisp/cl-http/cl-http-342/server/md5.lisp" 
#P"/Lisp/cl-http/cl-http-342/server/md5.xfasl") 

上面使用由MAKE-PATHNAME创建的路径名对象。它会返回所有匹配/Lisp/cl-http/cl-http-342/server/md5.*的文件。

这是一样的:

(directory "/Lisp/cl-http/cl-http-342/server/md5.*") 

其是较短的,但依赖于Unix的路径名的语法。

+0

+1 LISP中路径名的很好的总结,非常有帮助。 – Justicle 2009-09-10 23:08:54

8

实现目录列表的现代Common Lisp库是IOLIB

它的工作原理是这样的:

CL-USER> (iolib.os:list-directory "/etc/apt") 
(#/p/"trusted.gpg~" #/p/"secring.gpg" #/p/"trustdb.gpg" #/p/"sources.list" 
#/p/"sources.list~" #/p/"apt-file.conf" #/p/"apt.conf.d" #/p/"trusted.gpg" 
#/p/"sources.list.d") 

注意,不需要尾随斜线或通配符。它非常健壮,甚至可以用错误编码的unicode字符处理文件名。

的差异相比,CL-FAD:

  • 的对象,你得到的是IOLIB文件路径,为CL的路径名的替代品更接近底层的操作系统做什么。
  • IOLIB使用CFFI实现它的例程,所以它在所有Lisp实现(提供IOLIB具有操作系统的后端)上都是相同的,与CL-FAD相反,CL-FAD试图通过其所有的实现的DIRECTORY函数怪癖。
  • 与CL-FAD相比,iolib正确处理符号链接(CL-FAD的一个主要问题,使其在Windows IMHO以外的平台上几乎不可用)。
1

我会添加一个适用于我的示例,代码片段。我使用osicat(类似于cl-fad)和str

编辑:也与uiop:directory-files。 STR:含有?可以用search完成。

;; searching for "ref". 
(setf *data-directory* "~/books/lisp") 
(remove-if-not (lambda (it) 
        (str:contains? "ref" (namestring it))) 
       (osicat:list-directory *data-directory*)) 

回报

(#P"~/books/lisp/common-lisp-quick-reference-clqr-a4-booklet-all.pdf" 
#P"~/books/lisp/common-lisp-quick-reference-clqr-a4-consec.pdf" 
#P"~/books/lisp/commonLisp-interactive-approach-reference-buffalo.pdf") 

它当然可以提高我的正确使用通配符。但是这是你可以使用一个片段现在:)

参考文献: