news 2026/9/5 1:21:41

《elisp 每日一练》—— 低成本的文件读写

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《elisp 每日一练》—— 低成本的文件读写

上一节我们了解了文件读写的一些api,并且通过一个保存灵感的小例子了解了Emacs中文本的操作。实际在Emacs中读写文本无外乎两种目的,第一种是用户需要编辑文本并最终保存,第二种是要读取文件内容作为参数或者内容完成后续的工作。例如利用配置文件控制Emacs的行为或者插件的行为。

对于第一种我们可以使用正规的find-filefind-file-noselect将文件加载到一个buffer中,并且保存的时候使用save-buffer进行保存。但是这种方式太重了。Emacs在正式读写文件的时候有一些附加动作,如果我们只是简单的要里面的文本,这种开销有点太大了。今天我们主要介绍使用with-temp-fileinsert-file-contentswrite-region进行低成本的文件读写

背景知识

在上一节我们提到visit参数,但是我们没有详细展开,现在我们详细展开看看find-file-noselect在基础的读写需求上的额外操作。

首先它会通过visit参数构建一个访问关系,它会创建一个新的缓冲区,或者复用一个已存在的缓冲区。最关键的是,它会将缓冲区与文件“关联”起来。这意味着它会设置buffer-file-name并记录文件的修改时间,后续Emacs就将这个buffer和对应的文件关联起来了。

在读取文件的时候它还会额外进行编码转化,例如将文件由其他编码转化为utf-8,或者其他规定的编码。另外它也会进行文件格式的转化,也就是将DOS 格式的\r\n转化为\n

在打开文件之后,它会根据文件的类型设置文件的Major Mode。例如python文件会设置python-mode在该mode下可能会进行格式化、语法高亮等等操作。

在文件加载完之后,可能会调用find-file-hook让用户代码有机会执行额外的动作。

save-buffer也有一些额外的动作。

首先它会检查是否真的需要保存。它会根据我们前面介绍过的 buffer 的modified状态来判断当前是否需要保存。

接着它会进行额外的备份,例如将文件保存为foo~.txt这类与源文件类似的文件。

在真正执行写入操作之前,它会运行write-contents-functionswrite-file-functions这类hook函数,以便用户代码在写入前有机会介入,控制写入行为。

写入完成之后,它会更新buffer的状态,将它更新为未修改状态,并更新文件的上次修改时间。

从上面过程看,这两个函数纯粹就是为了让用户编辑文件所设计的,它纯粹是编辑器层面的函数。如果我们只是临时的读一些像保存上次退出保存的一些状态文件,下一次启动时用于恢复,对于这类临时文件,用户甚至都不知道该文件的存在。我们如果使用find-file-noselect这类的函数,就有点浪费了。

这种类型它们合适的方式是读取时使用with-temp-buffer+insert-file-contents来进行轻量级读取。如果要写入则采用write-region。如果你需要简单的操作buffer之后将buffer内容写入,可以使用with-temp-buffer。你可以将with-temp-file看成with-temp-buffer+insert-file-content+write-region的组合技。

练习

假设我们记录了多天的工作日志。每天的日志格式为:

** <2026-09-04 Fri> content content content .....

我们现在提供一个函数按日志查看某天的工作日志。

(defunmy/check-daily-work(date)"按输入日期DATE(格式 YYYY-MM-DD) 查看工作日志。"(interactive(list(read-string"Input date (YYYY-MM-DD): "(format-time-string"%Y-%m-%d"))))(let((content"")(foundnil)(collectingnil))(with-temp-buffer(when(file-exists-pmy/work-log-path)(insert-file-contentsmy/work-log-path)(let((lines(split-string(buffer-string)"\n"t)))(whilelines(let((line(carlines)))(cond;; 如果是日期标题行((string-prefix-p"** <"line)(ifcollecting;; 如果正在收集,说明遇到了下一个日期,停止收集并退出循环(setqlinesnil);; 否则检查是否匹配目标日期(when(string-match(concat"\\*\\* <"date)line)(setqfoundt)(setqcollectingt)(setqcontent(concatline"\n")))));; 如果是非标题行(t(whencollecting(setqcontent(concatcontent line"\n")))))(setqlines(cdrlines)))))))(if(notfound)(message"未找到 %s 的日志记录"date)(let((buffer(generate-new-buffer"WorkLog")))(switch-to-bufferbuffer)(erase-buffer)(insertcontent)))))

上述代码,我们通过 with-temp-buffer 创建一个临时的buffer,用来读取数据。处理时将所有数据按行划分,找到以**开头的日期行,如果当前日期匹配上目标日期,则将found设置为真,后面连着的几行是我们实际得到的当前的日志内容,如果后续又找到了**开头的内容表示到下一个日期了应该退出。

小结

本篇我们理解了find-file-noselect在临时读取数据的弊端,并且介绍了在这种情况下的一半处理方式。本篇的api函数在上一篇已经列举过了,这次就不在说明了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 1:11:19

解决高速差分PCB信号畸变,提升使用稳定性

精准的布线阻抗匹配是高速差分信号稳定的基础&#xff0c;而合理的端接阻抗匹配&#xff0c;是消除信号反射、优化波形质量、保障PCB长期稳定使用的关键。很多高速PCB布线参数完全达标&#xff0c;但设备仍存在高速传输闪断、眼图不达标、振铃过冲严重等问题&#xff0c;核心原…

作者头像 李华
网站建设 2026/9/5 1:08:45

秦陵铜车马逆向工程解析 —— 大型青铜分铸组装、薄壁构件、金属销铆铰接系统

秦陵铜车马逆向工程解析 —— 大型青铜分铸组装、薄壁构件、金属销铆铰接系统摘要秦陵一、二号铜车马是秦代官营青铜制造业的巅峰实物标本&#xff0c;整车由数千件青铜构件通过分铸、铸接、销接、铆接、铰接等多重工艺完成装配&#xff0c;实现大尺度器物与薄壁构件的工程平衡…

作者头像 李华
网站建设 2026/9/5 0:58:13

基于YOLOv5与DeepSORT的智能交通系统:车辆检测、车牌识别与车速估算实战

简介&#xff1a;这是一套面向计算机、人工智能与自动化专业学生及初学者的交通场景智能分析系统源码&#xff0c;聚焦车辆与行人检测、车牌识别、车型分类、车速估算及多目标跟踪等核心任务&#xff0c;适用于课程设计、毕业设计与算法实践。资源包共2000个文件&#xff0c;含…

作者头像 李华
网站建设 2026/9/5 0:39:07

实测降AI率平台效果!哪个工具网站更好用性价比更高?

最近后台快被私信炸毁了&#xff0c;清一色都是同一个问题&#xff1a;"论文AI率90%&#xff0c;学校用知网查&#xff0c;有没有靠谱的降AI工具&#xff1f;"作为一个帮三个学弟学妹成功通过盲审的过来人&#xff0c;我想说&#xff1a;选错工具&#xff0c;轻则白花…

作者头像 李华
网站建设 2026/9/5 0:33:34

国家层面定向钓鱼活动的威胁特征与全域防御路径研究

摘要 国家背景威胁组织发起的定向钓鱼活动&#xff0c;区别于普通商业黑产钓鱼&#xff0c;以情报窃取为核心目标&#xff0c;综合利用被攻陷邮箱横向扩散、仿冒域名、本地化语言诱饵、定制恶意载荷等手段&#xff0c;将政府机构、通信、医疗、高校、中小企业纳入攻击范围。该…

作者头像 李华