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

时间:2018-10-16 05:24:58

标签: common-lisp

我想打开一个文件并阅读其内容,如果文件不存在,请执行其他操作。

前者可以很容易地完成:CI_DB_mysqli_result Object ( [conn_id] => mysqli Object ( [affected_rows] => 1 [client_info] => mysqlnd 5.0.12-dev - 20150407 - $Id: 241ae00989d1995ffcbbf63d579943635faf9972 $ [client_version] => 50012 [connect_errno] => 0 [connect_error] => [errno] => 0 [error] => [error_list] => Array ( ) [field_count] => 6 [host_info] => localhost via TCP/IP [info] => [insert_id] => 0 [server_info] => 5.5.5-10.1.16-MariaDB [server_version] => 50505 [stat] => Uptime: 250329 Threads: 1 Questions: 4886 Slow queries: 0 Opens: 40 Flush tables: 1 Open tables: 29 Queries per second avg: 0.019 [sqlstate] => 00000 [protocol_version] => 10 [thread_id] => 353 [warning_count] => 0 ) [result_id] => mysqli_result Object ( [current_field] => 0 [field_count] => 6 [lengths] => [num_rows] => 1 [type] => 0 ) [result_array] => Array ( ) [result_object] => Array ( ) [custom_result_object] => Array ( ) [current_row] => 0 [num_rows] => [row_data] => )

对于后者,我的第一个想法是使用with-open-file来捕获错误,但是SBCL表示它是handler-case,这听起来像是编译器的内部符号,因此大概是不可移植的。

什么是便携式方法?

3 个答案:

答案 0 :(得分:8)

使用: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)))

路径名不存在:

(test #P"/hopefully/path/does/not/exist")
=> :SOMETHING-ELSE

使用现有路径名:

(test #P"/dev/urandom")
=> 123

您也可以使用PROBE-FILE来检查文件是否存在,如Rainer所述,但是在probe-file成功返回之后但实际打开文件之前,您可能会冒着被另一个进程删除文件的风险。

  

对于后者,我的第一个想法是使用处理程序大小写来捕获错误,但是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>)
...

上面所说的是,在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>)
...

答案 1 :(得分:5)

在这种情况下要处理的可移植错误类型为file-error(请参见CLHS)。

答案 2 :(得分:2)

如果要简单创建:

(with-open-file (foo "path/to/non-existing-file" :direction :output
                                                 :if-does-not-exist :create)
  ;; do your duty on stream `foo`)

如果还有其他操作,则将foo绑定到nil并给出有关这种情况的说明:

 (with-open-file (foo "no-such-file" :direction :output :if-does-not-exist nil)
   (when foo 
     ;; if file exists do what you intended
     ;; explicitely return a value with `(return ...)`
     )
   (unless foo 
     ;; catch the case that `foo` is bound to nil
     ;; so these are instructions for the `file doesn't exist` case 
     ))

如果文件不存在,则nil绑定到foo。 然后可以测试nil并知道打开文件是否成功。