个人微薄: weibo.com/manuscola
分类: LINUX
2013-01-28 23:04:47
学习一门语言,除了基本的控制操作外,文件系统API也是很重要的,最近学习了LISP的文件系统API ,和大家分享下心得。
open是很简单的接口,如下所示:
(open "/path/to/file.txt")
open之后,返回文件描述符,或者说是实用common lisp编程提到的stream 流。我们可以调用read-char或者read-line来读取文件的一个字符或者一行。 下面请看一段示例code:
(defun first-line(filename) (let ((in (open filename ))) (format t "~a~%" (read-line in)) (close in) ) ) (first-line "month.lisp" ) (first-line "notexist")
我们可以看到我们尝试输出month.lisp文件的第一行和notexist文件的第一行。看下输出的效果:
root@manu:~/code/lisp# clisp first-line.fas (defun leap-year(year) *** - OPEN: File #P"/home/manu/code/lisp/notexist" does not exist root@manu:~/code/lisp#
对于已经存在的文件,我们输出第一行的内容,对于不存在的内容,我们报了一个错,这表明,仅仅调用open,而不判断返回值是不行的。
对于读打开,如果文件不存在,有不想open报错,可以使用if-does-not-exist 关键字选项来指定不同的行为。
error :报错,这是默认行为。
create :如果不存在,则创建文件
NIL :返回NIL 来替代stream 。
下面我们看一个改进版的读取文件的第一行:
(defun first-line(filename) (let ((in (open filename :if-does-not-exist NIL))) (when in (format t "~a~%" (read-line in)) (close in) ) ) ) (first-line "month.lisp" ) (first-line "notexist")
OK ,这样就不会出现报错了。
刚才学到的是读打开,对于写打开,我们需要在调用open的时候,执行direction参数为output。
(open “file_w” :direction :output :if-exists :supersede)
上面的code的意思是写打开名为file_w的文件。对于写打开,open会期待文件不存在,对于文件存在的情形,可以通过指定if-exists来指定如何处理
下面展示一段code
(defun write-file (filename content) (let ((stream (open filename :direction :output :if-exists :supersede))) (format stream "~A ~%" content) (close stream) ) ) (write-file "file_w" "hello world")
这段代码的输出如下:
root@manu:~/code/lisp# cat file_w hello world root@manu:~/code/lisp#
cat是shell常用的一个指令,他会将文件的内容输出到终端上。 对于open,经常犯的错误是忘记close。这会造成句柄的泄漏。LISP提供了with-open-file这个宏,来保护这种情况。这个宏会确保返回前close stream。
下面看下cat的lisp实现:
(defun pseudo-cat (file) (with-open-file (str file :direction :input) (do ( (line (read-line str nil 'eof) (read-line str nil 'eof))) ((eql line 'eof)) (format t "~A~%" line) ) ) )
(pseudo-cat "month.lisp")
在linux中提供了POSIX接口stat,可以获取文件的信息,比如文件的类型(LINUX下7中type)获取文件的长度。从我这个初学者的角度来看,LISP做的不好,没有这种接口,需要编码产生。 LISP中提供了一个file-length的接口,可以获取文件的长度,可惜的是,入参是stream,而不是pathname。 我下面封装了一个获取文件长度的接口:
(defun file-len (filename) (with-open-file (in filename :element-type '(unsigned-byte 8)) (file-length in ) ) ) (format t "file len is ~A ~%" (file-len "month.lisp"))
输出如下:
root@manu:~/code/lisp# clisp file-len.fas file len is 503 root@manu:~/code/lisp#
LISP提供了删除的接口delete-file,还有rename-file的重命名接口,比较简单,我就不多说了。
总体来说,LISP的文件操作很奇怪,我学习过C的文件操作,python的和C的几乎一样,可是lisp可能是由于出世太早,看不到posix标准的影子。
1 实用Common Lisp编程
2 ANSI COMMON LISP中文版