如果文件不存在,请打开文件或执行其他操作

rwa*_*ace 2 common-lisp

我想打开一个文件并读取内容,或者如果该文件不存在则执行其他操作.

前者可以很容易地完成:with-open-file.

对于后者,我的第一个想法是用来handler-case捕捉错误,但SBCL说它是SB-INT:SIMPLE-FILE-ERROR,这听起来像编译器内部符号,因此可能是不可移植的.

可移植的方法是什么?

cor*_*ump 9

使用:if-does-not-exist nil(见OPEN):

(defun test (path)
  (with-open-file (stream path
                          :if-does-not-exist nil
                          :element-type '(unsigned-byte 8))
    (if stream
        (read-byte stream)
        :something-else)))
Run Code Online (Sandbox Code Playgroud)

使用不存在的路径名:

(test #P"/hopefully/path/does/not/exist")
=> :SOMETHING-ELSE
Run Code Online (Sandbox Code Playgroud)

使用现有路径名:

(test #P"/dev/urandom")
=> 123
Run Code Online (Sandbox Code Playgroud)

您也可以使用PROBE-FILE来检查文件是否存在,如Rainer所解释的那样,但是在probe-file成功返回之后但在实际打开文件之前,您可能会被另一个进程删除该文件.

对于后者,我的第一个想法是使用handler-case来捕获错误,但是SBCL说它是SB-INT:SIMPLE-FILE-ERROR,它听起来像编译器内部符号,因此可能是不可移植的.

当您捕获特定于实现的错误时,您可以尝试检查其类层次结构以查找名称属于Common-Lisp包的最近的超类:

CL-USER> (inspect (find-class 'SB-INT:SIMPLE-FILE-ERROR)) 

The object is a STANDARD-OBJECT of type SB-PCL::CONDITION-CLASS.
0. %TYPE: (CLASS #<SB-PCL::CONDITION-CLASS SB-INT:SIMPLE-FILE-ERROR>)
...
5. DIRECT-SUPERCLASSES: (#<SB-PCL::CONDITION-CLASS COMMON-LISP:SIMPLE-CONDITION>
                         #<SB-PCL::CONDITION-CLASS COMMON-LISP:FILE-ERROR>)
6. DIRECT-SUBCLASSES: NIL
...
11. %CLASS-PRECEDENCE-LIST: (#<SB-PCL::CONDITION-CLASS SB-INT:SIMPLE-FILE-ERROR>
                             #<SB-PCL::CONDITION-CLASS COMMON-LISP:SIMPLE-CONDITION>
                             #<SB-PCL::CONDITION-CLASS COMMON-LISP:FILE-ERROR>
                             #<SB-PCL::CONDITION-CLASS COMMON-LISP:ERROR>
                             #<SB-PCL::CONDITION-CLASS COMMON-LISP:SERIOUS-CONDITION>
                             #<SB-PCL::CONDITION-CLASS COMMON-LISP:CONDITION>
                             #<SB-PCL::SLOT-CLASS SB-PCL::SLOT-OBJECT>
                             #<SB-PCL:SYSTEM-CLASS COMMON-LISP:T>)
...
Run Code Online (Sandbox Code Playgroud)

上面所说的是,在SBCL中,SB-INT:SIMPLE-FILE-ERROR有两个直接的超类,其中一个是COMMON-LISP:FILE-ERROR.

这是另一个使用CCL的例子:

? (handler-case (open #P"/tmp/foo/bar/baz/foo") (error (e) (inspect e)))

[0]     #<CCL::SIMPLE-FILE-ERROR #x3020004DE7ED>
[1]     Class: #<STANDARD-CLASS CCL::SIMPLE-FILE-ERROR>
[2]     Wrapper: #<CCL::CLASS-WRAPPER CCL::SIMPLE-FILE-ERROR #x3020000F62DD>
        Instance slots
[3]     PATHNAME: #P"/tmp/foo/bar/baz/foo"
[4]     CCL::ERROR-TYPE: "No such file or directory : ~s"
[5]     CCL::FORMAT-CONTROL: #<Unbound>
[6]     CCL::FORMAT-ARGUMENTS: (NIL)
Inspect> 1
[0]     #<STANDARD-CLASS CCL::SIMPLE-FILE-ERROR>
[1]     Class: #<STANDARD-CLASS STANDARD-CLASS>
...
[6]     CCL::PRECEDENCE-LIST: (#<STANDARD-CLASS CCL::SIMPLE-FILE-ERROR>
                       #<STANDARD-CLASS SIMPLE-CONDITION>
                       #<STANDARD-CLASS FILE-ERROR> #<STANDARD-CLASS ERROR>
                       #<STANDARD-CLASS SERIOUS-CONDITION> ...)
...
[8]     CCL::DIRECT-SUPERCLASSES: (#<STANDARD-CLASS SIMPLE-CONDITION>
                           #<STANDARD-CLASS FILE-ERROR>)
...
Run Code Online (Sandbox Code Playgroud)


Sva*_*nte 5

要处理这种情况的便携式错误类型是file-error(参见CLHS).