Как мне перебрать каталог в Common Lisp? - PullRequest
23 голосов
/ 10 сентября 2009

Я использую OpenMCL в Дарвине, и я хотел бы сделать что-то вроде:

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

Но я не могу заставить directory вернуть что-либо, кроме NIL, и я не могу найти в Интернете ни одного хорошего объяснения (кроме "оно разное для каждой системы").

Есть указатели?

Ответы [ 4 ]

27 голосов
/ 10 сентября 2009

Существует два основных способа указания путей:

  • с использованием строк

Строки, очевидно, зависят от платформы: например, синтаксис Unix против синтаксиса Windows.

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

Вы можете создать объект pathname из строки:

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

Приведенный выше #p гарантирует, что объект пути (а не строка) будет создан, когда вы прочитаете его обратно.

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

Итак, Common Common Lisp внутренне работает с объектами имён путей, но он позволяет вам использовать обычные строки и при необходимости делает из них объекты имён.

Когда Common Lisp видит путь, в котором указаны не все компоненты (например, отсутствует каталог), он заполняет компоненты из объекта pathname, который является значением переменной * DEFAULT-PATHNAME-DEFAULTS *.

С помощью функции DESCRIBE вы можете просмотреть компоненты пути (здесь 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, создающих объекты pathname

MAKE-PATHNAME - это функция, для определения компонентов которой требуется несколько ключевых слов.

Иногда также полезно создать новое имя пути на основе существующего:

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

Если вы используете DIRECTORY, полезно использовать путь с подстановочными знаками. DIRECTORY затем вернет список подходящих путей. Имя «DIRECTORY» немного вводит в заблуждение, поскольку DIRECTORY не перечисляет содержимое каталога, но перечисляет совпадающие пути для (обычно) пути с подстановочными знаками. Подстановочные знаки могут соответствовать последовательности символов в таких компонентах, как /foo/s*c/list*.l* ". Существует также подстановочный знак **, который используется для сопоставления с частями иерархии каталогов, например / foo / ** /test.lisp, который соответствует всем файлам test.lisp в каталоге foo и его подкаталогах.

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

Выше должен возвращать список всех файлов 'lisp' в '/ Users / foo / Lisp /' и всех его подкаталогах.

Чтобы вернуть файлы .c в одном каталоге, используйте:

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

Обратите внимание, что DIRECTORY возвращает список объектов pathname (не список строк).

? (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 pathname.

18 голосов
/ 10 сентября 2009

Содержит ли ваша спецификация пути подстановочный знак? Путь к путевым именам Common Lisp поначалу несколько сложен для восприятия - по крайней мере, для меня это было ... Как CLHS указывает на функцию directory:

Если pathspec не дикий, то итоговый список будет содержать либо ноль или один элемент.

Чтобы ваше имя пути включало подстановочный знак, вы можете попробовать функцию make-pathname, например

(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.

8 голосов
/ 28 октября 2009

Современная библиотека 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")

Обратите внимание, что косая черта или подстановочные знаки не требуются. Он очень надежен и может даже обрабатывать имена файлов с неправильно закодированными символами Юникода.

Отличия от CL-FAD:

  • Объекты, которые вы получаете, - это пути к файлам IOLIB, замена имен путей CL, которая ближе к тому, что делает базовая ОС.
  • IOLIB реализует свои подпрограммы с использованием CFFI, поэтому он работает одинаково во всех реализациях Lisp (при условии, что IOLIB имеет внутренний интерфейс для операционной системы), в отличие от CL-FAD, который пытается абстрагироваться от функции DIRECTORY реализации со всеми причуды.
  • В отличие от CL-FAD, iolib корректно работает с символическими ссылками (одна из основных проблем с CL-FAD, которая делает его практически непригодным для использования на платформах, отличных от Windows IMHO).
2 голосов
/ 31 января 2018

Я добавлю пример, который работает для меня, ради фрагмента кода. Я использую osicat (аналог cl-fad) и str .

edit : также с uiop:directory-files. ул: содержит? может быть сделано с 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")

Конечно, это может быть улучшено, если правильно использовать подстановочные знаки. Однако это фрагмент, который вы можете использовать прямо сейчас:)

Ссылки:

...