如何在Common Lisp中遍历目录?

如何在Common Lisp中遍历目录?,lisp,filesystems,directory,common-lisp,Lisp,Filesystems,Directory,Common Lisp,我在达尔文使用OpenMCL,我想做一些类似的事情: (loop for f in (directory "somedir") collect (some-per-file-processing f)) 但是我无法让目录返回除NIL之外的任何内容,而且我似乎也无法在网上找到任何好的解释(除了“每个系统都不同”) 有指针吗?您的路径名规范是否包含通配符?Common Lisp的路径名一开始有点难理解-至少对我来说是。。。与目录功能上的状态相同: 如果pathspec不是wild,则 结果列表

我在达尔文使用OpenMCL,我想做一些类似的事情:

(loop for f in (directory "somedir")
  collect (some-per-file-processing f))
但是我无法让
目录
返回除
NIL
之外的任何内容,而且我似乎也无法在网上找到任何好的解释(除了“每个系统都不同”)


有指针吗?

您的路径名规范是否包含通配符?Common Lisp的路径名一开始有点难理解-至少对我来说是。。。与
目录
功能上的状态相同:

如果pathspec不是wild,则 结果列表将包含 零或一个元素

为了让您的路径名包含通配符,您可以尝试使用makepathname函数,如

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

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

我发现这个库对处理路径名和文件系统有很大帮助。特别是,它的函数可能比普通标准的
目录
函数更易于使用。

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

  • 使用字符串
字符串显然取决于平台:例如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确保在读回pathname对象时创建了该对象(而不是字符串)

? #P"/Users/bar/foo.text"
#P"/Users/bar/foo.text"
因此,内部公共Lisp可以处理路径名对象,但它允许您使用普通字符串,并在需要时从中生成路径名对象

当Common Lisp看到未指定所有组件的路径名(例如,缺少目录)时,它将填充pathname对象中的组件,该对象是variabel*DEFAULT-pathname-DEFAULTS*的值

使用函数descripe,您可以查看路径名的组件(此处为Clozure CL):

如果使用目录,则使用带有通配符的路径名非常有用。目录将返回匹配路径名的列表。名称“DIRECTORY”有点误导,因为DIRECTORY不列出目录的内容,而是列出(通常)带有通配符的路径名的匹配路径名。通配符可以匹配组件中的字符序列,如/foo/s*c/list*.l*”。还有通配符**,用于匹配目录层次结构的部分,如/foo/**/test.lisp,它匹配目录foo及其子目录下的所有文件test.lisp

(directory "/Users/foo/Lisp/**/*.lisp")
上面应该返回“/Users/foo/lisp/”及其所有子目录中所有“lisp”文件的列表

(directory "/Users/foo/Lisp/**/*.lisp")
要返回单个目录中的.c文件,请使用:

(directory "/Users/foo/c/src/*.c")
请注意,目录返回路径名对象列表(而不是字符串列表)

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

这与:

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

它较短,但取决于Unix路径名语法。

实现目录列表的现代公共Lisp库是

它的工作原理如下:

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的路径名,而CL的路径名更接近底层操作系统的功能
  • IOLIB使用CFFI实现它的例程,因此它在所有Lisp实现上都是一样的(前提是IOLIB有一个操作系统的后端),与CL-FAD相反,CL-FAD试图用它所有的怪癖来抽象实现的目录函数
  • 与CL-FAD相反,iolib正确处理符号链接(CL-FAD的一个主要问题是它在Windows IMHO以外的平台上几乎不可用)

为了编写代码片段,我将添加一个适合我的示例。我使用(类似于cl fad)和

编辑:也可使用
uiop:directory files
。str:contains?可通过
搜索
完成

;; 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")
如果能正确使用通配符,这当然是可以改进的

参考资料:


Yep为我工作-(目录“pathname”)返回NIL,其中(目录“pathname/*.*)给了我预期的结果。您只需要名称包含点的文件?奇怪吧?我实际上是在寻找.h和.cpp文件,但“pathname/*”返回NIL。可能与Lisp合并“不完整”的方式有关“路径名具有一些默认值。由于“/path/*”只包含名称的通配符,而不包含类型的通配符,我猜CCL只是从默认路径名或其他内容中获取要查找的类型。我经常被一个毫无根据的假设所困扰,即shell中有效的路径名/模式也是有效的/等效的Lisp路径名
;; 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")