Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3892038
  • 博文数量: 146
  • 博客积分: 3918
  • 博客等级: 少校
  • 技术积分: 8585
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-17 13:52
个人简介

个人微薄: weibo.com/manuscola

文章分类

全部博文(146)

文章存档

2016年(3)

2015年(2)

2014年(5)

2013年(42)

2012年(31)

2011年(58)

2010年(5)

分类: LINUX

2013-01-28 23:04:47

Lisp之文件系统

学习一门语言,除了基本的控制操作外,文件系统API也是很重要的,最近学习了LISP的文件系统API ,和大家分享下心得。

open

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 关键字选项来指定不同的行为。

  1. error :报错,这是默认行为。

  2. create :如果不存在,则创建文件

  3. 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来指定如何处理

  1. supersede: 替换
  2. append : 追加写
  3. overwirte:覆盖写
  4. NIL :返回NIL而不是stream

下面展示一段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的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中文版

阅读(11572) | 评论(2) | 转发(2) |
给主人留下些什么吧!~~

Bean_lee2013-02-05 22:06:04

lmnos:这语言看上去好复杂

呵呵刚开始看Lisp的时候是会有这种感觉。呵呵,学习起来都一样。我学C语言的时候,疼痛感最强,现在已经很舒服了。
学起来还好,向你推荐。

回复 | 举报

lmnos2013-02-05 11:57:33

这语言看上去好复杂