《elisp 每日一练》——目录的CRUD

《elisp 每日一练》——目录的CRUD

Masimaro
2026-09-08 / 0 评论 / 0 阅读 / 正在检测是否收录...

在之前的一系列的文章中,我们讨论了有关文件的一些操作,包括文件读写与文件的属性。我们今天开始讨论目录的操作

背景知识

我们今天来讨论目录的CRUD,所谓的CRUD也就是我们常说的增删改查。目录内由多个文件和目录组成,所以它的增删改查也就是操作里面的文件和目录以及获取目录中的子元素。

路径

我们首先还是介绍一些与路径有关的函数

  • file-directory-p 判断路径是否为目录
  • file-name-as-directory 确保传入的路径末尾有 / ,这在我们拼接路径时很有用

所以对于一个陌生的路径,我们可以先通过 file-exists-p(函数不区分是文件或者目录,只判断路径是否真实存在) 判断它是否存在。如果存在的话可以使用 file-regular-pfile-directory-p 判断是否是文件或者目录,如果是目录可以通过 file-name-as-directory 返回一个末尾带 / 的标准目录路径

列目录与属性

我们查询目录一般是查询目录中的文件和子目录,查询目录中的文件可以使用 directory-files 。它的函数签名如下:

(directory-files DIR &optional FULL MATCH NOSORT COUNT)
  • DIR 表示要查询的目录
  • FULLt 时表示返回目录中子文件和目录的全路径
  • MATCH 是一个正则表达式,用来筛选指定条件的子内容
  • NOSORT 对输出的目录内容不排序
  • COUNT 如果目录下文件太多了,我们可以使用这个参数限制返回的数据项

在Linux中,文件与目录的属性是类似的,所以目录的属性实际也可以使用 file-attributes 来获取。对于目录中所有文件的属性获取,常规的方式是遍历 directory-files 中列举的文件和目录名称,最后对每个文件或者目录使用 file-attributes 获取属性。这个工作Emacs在底层的C代码端已经帮我们做了,我们可以通过 directory-files-and-attributes 一次性获得目录的所有内容以及对应的属性。它的函数原形如下:

(directory-files-and-attributes DIRECTORY &optional FULL MATCH NOSORT ID-FORMAT COUNT)

它的函数原形就是 directory-filesfile-attributes 的组合。返回值类似于 ((FILE1 . FILE1-ATTRS) (FILE2 . FILE2-ATTRS) ...) , FILE是文件的名称,FILE-ATTRS 是文件属性,属性的组织方式与 file-attributes 的返回值一样。

文件操作

针对文件和目录的增删,有以下函数可以了解一下:

  • make-directory 创建目录,它可以额外接受一个 PARENTS 参数,该参数为 t 时可以递归创建,相对于 mkdir -p
  • rename-file 移动或者重命名文件和目录,OK-IF-ALREADY-EXISTS 参数如果为 t 则会覆盖同名文件,否则报错
  • copy-file 复制文件
  • copy-directory 复制目录,默认递归复制所有子目录
  • delete-file 删除文件
  • delete-directory 删除目录

练习

至此我们对目录的操作差多不都了解完了,本次的练习我在上一节的基础上完成一个简单的查看目录或者文件属性的功能。

(defun my/format-file-attribute (filename attrs)
  "格式化文件名和文件属性
FILENAME 为文件名
ATTRS 为 file-attributes 返回的属性列表"
  (let ((modes (file-attribute-modes attrs))
        (owner (file-attribute-user-id attrs))
        (group (file-attribute-group-id attrs))
        (size (file-attribute-size attrs))
        (modified-time (format-time-string "%Y-%m-%d %H:%M:%S" (file-attribute-modification-time attrs))))
    (format "%-11s %-8s %-8s %8d Bytes %s %s"
                modes
                owner
                group
                size
                modified-time
                filename)))

(defun my/list-directory-attribute(dir-path)
  "在新buffer中列出所有文件和子目录"
  (interactive "fDirPath: ")
  (let ((abs-dir-path (expand-file-name dir-path)))
    ;;路劲必须存在并且为目录
    (if (and (file-exists-p abs-dir-path) (file-directory-p abs-dir-path))
        (let* ((file-attrs (directory-files-and-attributes abs-dir-path))
               (buffer (get-buffer "DirAttribute")))
          (if (not buffer)
                (setq buffer (get-buffer-create "DirAttribute"))
            (switch-to-buffer buffer)
            (setq-local buffer-dir-path abs-dir-path)
          (erase-buffer)
          (goto-char (point-min))
          (dolist (file-and-attr file-attrs)
            (let* ((filename (car file-and-attr))
                   (attr (cdr file-and-attr))
                   (attr-string (my/format-file-attribute filename attr)))
              (insert attr-string)
              (add-text-properties (point) (1- (point)) `(file-name ,filename))
              (newline))))))))

这些代码与上一篇的基本类似,我们新加了一个属性用于记录当前行对应的文件名,并且添加了一个 buffer local 变量,记录当前buffer对应的是哪个目录的内容。后续我们可以定义一系列的文件和目录操作的函数, 可以以 buffer local 为基础实现文件的拷贝、重命名等快速操作

小结

本节我们介绍了目录和文件的属性以及一些操作,本节介绍的api函数如下:

  • file-directory-p
  • file-name-as-directory
  • directory-files
  • directory-files-and-attributes
  • make-directory
  • rename-file
  • copy-file
  • copy-directory
  • delete-file
  • delete-directory
0

评论 (0)

取消