我想打开一个文件并阅读其内容,如果文件不存在,请执行其他操作。
前者可以很容易地完成: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
,这听起来像是编译器的内部符号,因此大概是不可移植的。
什么是便携式方法?
答案 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
并知道打开文件是否成功。