本节主要介绍UIOP中的一些有关文件和文件操作方面的使用。获取你也应该直接看一看UIOP的官方文档.
当然,也别忘了
测试文件是否存在
probe-file 专门用来测试文件是否存在。如果返回Nil文件不存在,返回truename则文件存在
truename
Many file systems permit more than one filename to designate a particular file.
Even where multiple names are possible, most file systems have a convention for generating a canonical filename in such situations. Such a canonical filename (or the pathname representing such a filename) is called a truename.
为了可移植性,可以使用返回pathname的uiop:probe-file* 或者uiop:file-exists-p(如果文件存在的话)
1
2
3
4
5
6
7
8
9
10
|
$ ln -s /etc/passwd foo
(probe-file "/etc/passwd")
#p"/etc/passwd"
(probe-file "foo")
#p"/etc/passwd"
(probe-file "bar")
NIL
|
展开~(家目录环境变量)
我们使用uiop:native-namestring:
1
|
(uiop:native-namestring "~/.emacs.d/")
|
如果文件不存在,他也会被展开
1
2
|
(uiop:native-namestring "~/foo987.txt")
;; "/home/me/foo987.txt"
|
在许多lisp实现上(CCL,ABCL,ECL,CLISP,LispWorks),namestring 很像。在 SBCL上,如果文件不存在,或者目录不存在,namestring不会展开path 而是直接返回参数
要测试文件是否存在也可以使用truename,但是在SBCL上,如果文件不存在,会直接返回错误。
创建文件夹
1
|
(ensure-directories-exist "fbbboo/bar/baz/")
|
这样会创建fbbboo bar baz 不要忘记在尾部加上斜杠
删除文件夹
uiop:delete-directory-tree 和一个pathname(#p),一个尾部斜杠 和:validate
1
|
(uiop:delete-directory-tree #p"dirtest/" :validate t)
|
也可以使用pathname 函数创建一个pathname
1
2
|
(defun rmdir (path)
(uiop:delete-directory-tree (pathname path) :validate t))
|
uiop 还有一个delete-empty-directory 用来删除空的文件夹
合并文件和文件夹
merge-pathnames 专用来合并路径,如果你想在后面添加一个文件夹,第二个参数必须带上末尾斜杠
1
2
|
(merge-pathnames "otherpath" "/home/vince/projects/")
;; => #p"/home/vince/projects/otherpath" 这里otherpath被当做文件
|
1
2
3
|
(merge-pathnames "otherpath" "/home/vince/projects")
;; #P"/home/vince/otherpath"
;; ^^ no "projects", because it was seen as a file.
|
1
2
3
|
(merge-pathnames "otherpath/" "/home/vince/projects")
;; #P"/home/vince/otherpath/projects"
;; ^^ inserted here
|
获取当前目录(CWD)
使用uiop/os:getcwd:
1
2
3
|
(uiop/os:getcwd)
;; #P"/home/vince/projects/cl-cookbook/"
;; ^ with a trailing slash, useful for merge-pathnames
|
获取以lisp工程为根目录的相对路径的绝对路径
使用asdf:system-relative-pathname system path.
1
2
|
(asdf:system-relative-pathname "mysystem" "src/web")
;; => #P"/home/vince/projects/mysystem/src/web/"
|
opening a file
打开文件其实之前有写过,这里不赘述。直接给出cookbook 的连接(主要,我自己已经看过了,不想多写哈哈哈哈)
opening a file
也可以去看看我之前写的Input-Output
Reading files
将文件读入string 或 行list中
- read-file-string
1
|
(uiop:read-file-string "file.txt")
|
- read-file-lines
1
|
(uiop:read-file-lines "file.txt")
|
read-line or read-char
这两个函数的性能不高,可以加入缓冲区解决这个问题
1
2
3
4
5
6
|
(with-output-to-string (out)
(with-open-file (in "/path/to/big/file")
(loop with buffer = (make-array 8192 :element-type 'character)
for n-characters = (read-sequence buffer in)
while (< 0 n-characters)
do (write-sequence buffer out :start 0 :end n-characters))))
|
以utf-8的格式读取
1
2
3
|
(with-open-file (in "/path/to/big/file"
:external-format :utf-8)
)
|
将SBCL的默认字符集设为utf-8
在~/.sbclrc中加入
1
2
3
4
5
|
(setf sb-impl::*default-external-format* :utf-8)
或者
(setf sb-alien::*default-c-string-external-format* :utf-8)
|
向文件中写入内容
1
2
3
4
|
(with-open-file (f <pathname> :direction :output
:if-exists :supersede
:if-does-not-exist :create)
(write-sequence s f))
|
如果文件存在,你也可以使用:append 来追加内容
使用库
Alexandria 有一个函数叫write-string-into-file
1
|
(alexandria:write-string-into-file content "file.txt")
|
获取文件后缀
1
|
(pathname-type "~/foo.org") ;; => "org"
|
获取文件属性(size,access time,….)
Osicat(in quicklisp)是一个轻量级操作系统接口。使用Osicat 可以获取环境变量,操作files directories pathnames
1
2
3
4
|
(ql:quickload "osicat")
(let ((stat (osicat-posix:stat #P"./files.md")))
(osicat-posix:stat-size stat)) ;; => 10629
|
可以使用以下函数获取更多的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
|
osicat-posix:stat-dev
osicat-posix:stat-gid
osicat-posix:stat-ino
osicat-posix:stat-uid
osicat-posix:stat-mode
osicat-posix:stat-rdev
osicat-posix:stat-size
osicat-posix:stat-atime
osicat-posix:stat-ctime
osicat-posix:stat-mtime
osicat-posix:stat-nlink
osicat-posix:stat-blocks
osicat-posix:stat-blksize
|
列出所有的文件和文件夹
有些函数可以返回pathnames
1
2
3
|
(namestring #p"/foo/bar/baz.txt") ==> "/foo/bar/baz.txt"
(directory-namestring #p"/foo/bar/baz.txt") ==> "/foo/bar/"
(file-namestring #p"/foo/bar/baz.txt") ==> "baz.txt"
|
返回文件夹中的文件(不包括文件夹)
1
|
(uiop:directory-files "./")
|
返回一连串的pathnames:
1
2
3
4
5
6
7
8
|
(#P"/home/vince/projects/cl-cookbook/.emacs"
#P"/home/vince/projects/cl-cookbook/.gitignore"
#P"/home/vince/projects/cl-cookbook/AppendixA.jpg"
#P"/home/vince/projects/cl-cookbook/AppendixB.jpg"
#P"/home/vince/projects/cl-cookbook/AppendixC.jpg"
#P"/home/vince/projects/cl-cookbook/CHANGELOG"
#P"/home/vince/projects/cl-cookbook/CONTRIBUTING.md"
[…]
|
返回所有的子文件夹
1
|
(uiop:subdirectories "/Users/qibinyang/test")
|
1
2
3
4
|
(#P"/Users/qibinyang/test/assertTest/" #P"/Users/qibinyang/test/center/"
#P"/Users/qibinyang/test/client1/" #P"/Users/qibinyang/test/client2/"
#P"/Users/qibinyang/test/test/")
|