Common Lisp 中独立于操作系统的路径名

Joã*_* Fé 3 lisp filesystems common-lisp

我想加载位于当前工作文件夹子目录中的 lisp 脚本。相对路径是./crossover-operators/ER.lisp

在 Linux 中,这是通过以下方式完成的:

(load "./crossover-operators/ER.lisp")
Run Code Online (Sandbox Code Playgroud)

在 Windows 中是通过以下方式完成的:

(load ".\\crossover-operators\\ER.lisp")
Run Code Online (Sandbox Code Playgroud)

如何创建一个独立于运行 Common Lisp 脚本的操作系统加载ER.lisp脚本的函数?

cor*_*ump 5

首先,19.1.1 Namestrings as Filenames确实表明,namestring(作为路径名的字符串)不可移植。

符合标准的程序绝不能无条件地使用除逻辑路径名名称串之外的文字名称串,因为 Common Lisp 没有定义任何名称串语法,但保证可移植的逻辑路径名除外。

另请注意,如果您向用户询问文件名,则可以便携地使用它们:

然而,一个符合标准的程序如果小心的话,可以成功地操作用户提供的包含或引用不可移植名称串的数据。

您有两个选项,其中一个选项互不排斥:使用路径名构造函数和/或使用逻辑路径名。

路径名构造函数

使用make-pathname,构建路径名merge-pathnames。路径名是一种可以组合在一起的不同组件(目录、名称、类型等)的结构。它们是使用原型继承方法构建的,您可以通过复制现有路径名并更改其某些组件来创建新路径名。

make-pathname就像 struct 构造函数一样,除了它有一个:defaults参数,该参数给出了用作原型的路径名。

merge-pathnames 有点不同,因为它也执行语义操作。

例如,如果*default-pathname-defaults*,保存默认路径名的特殊变量,设置如下:

USER> (setf *default-pathname-defaults*
            (make-pathname :directory '(:relative "crossover-operator")))
#P"crossover-operator/"
Run Code Online (Sandbox Code Playgroud)

那么你有两种不同的行为。

USER> (make-pathname :directory '(:relative "tmp")  
                     :defaults *default-pathname-defaults*)
#P"tmp/"
Run Code Online (Sandbox Code Playgroud)

make-pathname 替换原始路径名的目录组件。

USER> (merge-pathnames *)
#P"crossover-operator/tmp/"
Run Code Online (Sandbox Code Playgroud)

merge-pathnames取一个路径名(这里是我们刚刚构建的那个,用 表示*),并将目录相对于*default-pathname-defaults*.

逻辑路径名

逻辑路径名有点像 URL(统一资源定位器),只是间接表示文件。程序员必须根据地址部分定义从逻辑路径名到实际物理路径名的转换函数HOST

路径名(名称字符串)的打印表示不可移植,逻辑路径名除外。请参阅19.3.1 逻辑路径名名称字符串的语法

除了具有定义的语法和转换函数(从逻辑路径名到物理路径名)之外,它们的行为与其他路径名一样,因此您可以merge-pathnames如上所示进行调用。

路径名转换可以映射到不可移植的名称字符串(但您可以在不同的主机上设置不同的转换),但也可以映射到逻辑或物理路径名。hyperspec forLOGICAL-PATHNAME-TRANSLATIONS有一些关于如何使用逻辑路径名的示例,如下所示:

 ;;;A more complex example, dividing the files among two file servers
 ;;;and several different directories.  This Unix doesn't support
 ;;;:WILD-INFERIORS in the directory, so each directory level must
 ;;;be translated individually.  No file name or type translations
 ;;;are required except for .MAIL to .MBX.
 ;;;The namestring syntax on the right-hand side is implementation-dependent.
 (setf (logical-pathname-translations "prog")
       '(("RELEASED;*.*.*"        "MY-UNIX:/sys/bin/my-prog/")
         ("RELEASED;*;*.*.*"      "MY-UNIX:/sys/bin/my-prog/*/")
         ("EXPERIMENTAL;*.*.*"    "MY-UNIX:/usr/Joe/development/prog/")
         ("EXPERIMENTAL;DOCUMENTATION;*.*.*"
                                  "MY-VAX:SYS$DISK:[JOE.DOC]")
         ("EXPERIMENTAL;*;*.*.*"  "MY-UNIX:/usr/Joe/development/prog/*/")
         ("MAIL;**;*.MAIL"        "MY-VAX:SYS$DISK:[JOE.MAIL.PROG...]*.MBX")))

 ;;;Sample use of that logical pathname.  The return value
 ;;;is implementation-dependent.          
 (translate-logical-pathname "prog:mail;save;ideas.mail.3")
=>  #P"MY-VAX:SYS$DISK:[JOE.MAIL.PROG.SAVE]IDEAS.MBX.3"
Run Code Online (Sandbox Code Playgroud)