2.1 缓冲区名称

buffer-namebuffer-file-name 这两个函数展示了文件与缓冲区之间的区别。对以下表达式求值,(buffer-name) 会在回显区显示缓冲区的名称;而对 (buffer-file-name) 求值,会显示该缓冲区所引用文件的名称。通常,(buffer-name) 返回的名称与其引用的文件名称相同,而 (buffer-file-name) 返回的是文件的完整路径名。

文件和缓冲区是两种不同的实体。文件是永久记录在计算机中的信息(除非你删除它);而缓冲区是 Emacs 内部的信息,会在编辑会话结束时(或你关闭缓冲区时)消失。通常,缓冲区包含你从文件中复制的信息,我们说这个缓冲区正在访问(visiting)该文件。你所编辑和修改的正是这份副本。对缓冲区的修改不会改变文件,直到你保存该缓冲区。保存时,缓冲区的内容会被复制到文件中,从而永久保存。

如果你正在 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 变量。)

尽管文件和缓冲区有区别,但你常会发现人们用“文件”指代“缓冲区”,反之亦然。事实上,大多数人会说“我正在编辑一个文件”,而不是“我正在编辑一个很快会保存到文件中的缓冲区”。在上下文清晰的情况下,这种说法通常不会造成歧义。但在处理计算机程序时,必须牢记这种区别,因为计算机不像人类那样聪明。

顺便一提,“缓冲区(buffer)”一词源自其“缓冲碰撞冲击力的垫子”这一含义。在早期计算机中,缓冲区起到了缓冲文件与中央处理器之间交互的作用。存储文件的鼓形存储器或磁带与中央处理器是两种差异很大的设备,各自以不同的速度间歇工作。缓冲区的存在使它们能够高效地协同工作。最终,缓冲区从一个中介、临时存放地,演变为了实际进行工作的场所。这种转变就像一个小型海港发展成大城市:起初,它只是货物在装船前临时仓储的地方;后来,它自身成为了商业和文化中心。

并非所有缓冲区都与文件关联。例如,*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 是只读的,不允许修改缓冲区内容。但你可以在任何可编辑的缓冲区中使用此功能;在编写代码或文档(如本书)时,这个特性非常实用。