2.1 缓冲区名称

两个函数,buffer-namebuffer-file-name,展示了文件和缓冲区之间的区别。当你评估下面的表达式 (buffer-name) 时,缓冲区的名称会出现在回显区。当你评估 (buffer-file-name) 时,缓冲区所引用的文件的名称会出现在回显区。通常,由 (buffer-name) 返回的名称与它引用的文件的名称相同,而由 (buffer-file-name) 返回的名称是文件的完整路径名。

文件和缓冲区是两个不同的实体。文件是永久记录在计算机中的信息(除非你删除它)。另一方面,缓冲区是 Emacs 内部的信息,在编辑会话结束时(或者当你杀死缓冲区时)将会消失。通常,缓冲区包含你从文件中复制的信息;我们说缓冲区正在访问该文件。这份副本是你要操作和修改的。对缓冲区的更改不会影响文件,直到你保存缓冲区。当你保存缓冲区时,缓冲区被复制到文件中,因此被永久保存。

如果你正在 GNU Emacs 中的 Info 中阅读本文,你可以通过将光标定位在表达式后并键入 C-x C-e 来评估以下每个表达式。

(buffer-name)

(buffer-file-name)

在 Info 中执行 (buffer-name) 时,返回的值是 "*info*",而执行 (buffer-file-name) 时返回的值是 nil

另一方面,在我编写这个文档时,执行 (buffer-name) 返回的值是 "introduction.texinfo",而执行 (buffer-file-name) 返回的值是 "/gnu/work/intro/introduction.texinfo"

前者是缓冲区的名称,而后者是文件的名称。在 Info 中,缓冲区名称是 "*info*"。Info 没有指向任何文件,因此执行 (buffer-file-name) 的结果是 nil。符号 nil 源自拉丁语单词 "nothing",在这种情况下,它表示该缓冲区未关联任何文件。(在 Lisp 中,nil 也用于表示 "false",并且是空列表 () 的同义词。)

在编写文档时,我的缓冲区名称是 "introduction.texinfo"。它指向的文件名称是 "/gnu/work/intro/introduction.texinfo"

(在这些表达式中,括号告诉 Lisp 解释器将 buffer-namebuffer-file-name 视为函数;没有括号,解释器将尝试将这些符号评估为变量。See 变量。)

尽管文件和缓冲区之间有区别,但你经常会发现人们在指代文件时实际上是指缓冲区,反之亦然。实际上,大多数人会说:“我正在编辑一个文件”,而不是说:“我正在编辑一个缓冲区,稍后将保存到文件。” 从上下文中几乎总能清楚人们的意思。然而,在处理计算机程序时,保持区别是重要的,因为计算机没有人类那么智能。

顺便说一下,“缓冲区”这个词的意义来源于它作为减缓碰撞力的缓冲物。在早期计算机中,缓冲区起到了文件与计算机中央处理单元之间相互作用的缓冲作用。持有文件的磁鼓或磁带和中央处理单元是非常不同的设备,它们以各自的速度、断断续续地工作。缓冲区使它们能够有效地协同工作。最终,缓冲区从一个中介、一个临时存放的地方,发展成为工作完成的地方。这种转变有点像一个小港口发展成为一个大城市:曾经它只是在货物被装上船之前的临时仓库;然后它成为一个独立的商业和文化中心。

并非所有的缓冲区都与文件相关。例如,‘*scratch*‘ 缓冲区没有访问任何文件。同样,‘*Help*‘ 缓冲区也没有与任何文件相关。

在过去,当你没有 ‘~/.emacs‘ 文件,通过输入 ‘emacs‘ 命令启动 Emacs 会话时,不指定任何文件,Emacs 会以 ‘*scratch*‘ 缓冲区可见的状态启动。现在,你会看到一个启动画面。你可以按照启动画面上建议的命令之一,访问一个文件,或按 ‘q‘ 键退出启动画面并进入 ‘*scratch*‘ 缓冲区。

如果切换到 ‘*scratch*‘ 缓冲区,输入 ‘(buffer-name)‘,将光标定位到其后,然后键入 ‘C-x C-e‘ 以评估表达式。将返回并显示 ‘*scratch*‘ 的名称在回显区。‘*scratch*‘ 就是该缓冲区的名称。当你在 ‘*scratch*‘ 缓冲区中输入 ‘(buffer-file-name)‘ 并评估时,回显区将显示 ‘nil‘,就像在 Info 中评估 ‘(buffer-file-name)‘ 时一样。

顺便提一下,如果你在 ‘*scratch*‘ 缓冲区中,想要将表达式返回的值显示在 ‘*scratch*‘ 缓冲区本身而不是在回显区,可以键入 ‘C-u C-x C-e‘ 而不是 ‘C-x C-e‘。这将导致返回的值出现在表达式之后。缓冲区会看起来像这样:

(buffer-name)"*scratch*"

在 Info 中你不能这样做,因为 Info 是只读的,它不允许你更改缓冲区的内容。但是在任何你可以编辑的缓冲区中,你都可以这样做;当你编写代码或文档(比如这本书)时,这个功能非常有用。