虚拟文件系统(VFS)是一个抽象概念,它具有极其高效的用途。几种流行的语言现在都支持 VFS 构造,Cameron Laird 向您说明这些构造适用于什么。
“不亲自尝试就不会明白它是多么有用”。当有人对我这么说时,我一贯的反应就是认为说这话的人对所说的功能不够了解,所以没法说清楚。
但是,对于虚拟文件系统,亲身经历告诉我说这话的人是对的。 Jeffrey Hobbs 是 ActiveState Corp. 的高开发人员,我们俩都见识了使用虚拟文件系统(VFS)可以实现多么不可思议的强大功能。
简单的构想,重大的成果
VFS 背后的构想很简单:它将不是文件系统的事物表示为文件系统。这里的文件系统指的是“传统的类 Linux 文件系统”:由可直接访问的目录和(普通)文件构成的树或层次结构。当然,这个概念会激起所有 Linux 用户的兴趣,因为 Linux 本身的许多特征都源自 UNIX 文件系统内对设备、表和其它对象的表示。UNIX 建立在如下原则之上:每样东西(或者至少是许多东西)都是文件;VFS 将这一原则加以推广,将尽可能多的东西看成是文件系统。
注:Linux 内核工程师也谈到了 VFS,但意义不同。本月的专栏文章不是关于 Linux 虚拟文件系统交换器的,该交换器将文件系统驱动程序分派给 ext2、ext3、reiserfs 等等。
对 VFS 的一种看法是:它是某种技术或概念的另一个示例,用独立开发人员 Jean-Claude Wippler 的话说,这种技术“使 OS 和高级语言环境之间的界限变得模糊”。另外,“系统服务”在应用程序开发语言中的出现使可移植性变得更为容易,因为操作系统从视野中消失。
那么,哪类东西本身不是文件系统,但用这种方式表示却非常有用呢?这有许多:可以通过 FTP、HTTP、WebDAV 或其它网络协议访问的文件;.zip 文件、CVS(并发版本控制系统,concurrent versions system)或其它归档文件的内容;数据库表;受安全性或其它约束限制的真正文件系统的投影(projection);及其它。
容易看出这样的资源可以以自然的方式映射到文件系统。假定 example.zip 压缩了下面这些文件:
first
subdir1/second
subdir1/third
subdir2/fourth
该归档文件很可能创建为现有文件系统树的直接(局部)映像,所以自然可以用有根树表示:
./first
./subdir1/second
./subdir1/third
./subdir2/fourth
许多在业界有影响的产品都依赖于 VFS。象日志记录文件系统这样的 DB2 功能部件的体系结构就依靠于 VFS 模型。众所周知的 Zope 应用程序服务器提供了一个颇有挑战性的 VFS 示例。Zope 的“获得(acquisition)”概念将程序化的对象映射成 URL。在 Zope 中,类似于下面这样的方法调用:
context.myproject.object1.method1(year = "1999")
相当于对下面这个 URL 的 HTTP 请求:
http://myzope.com/myproject/object1/method1?year=1999
看出其中的优点了吗?VFS 和 UNIX 的“一切均是文件”的概念也很相似,因为这个想法很容易理解和模仿,但是要意识到它能将应用程序设计简化到哪种程度,还需要花几年工夫。
我们来研究一个示例。假定您已经编写了一个文本编辑器;它提供了访问、读取、修改单独文件以及将它们写回到存储器的方法。如果使用文件系统“虚拟器”,立刻就可以使用所有相同的代码来浏览 FTP 或 ZIP 归档文件,选择、修改并保存单独的项。您拥有在操作本地文件时能很好地工作的浏览器、备份实用程序、安全性扫描程序或版本控制系统吗?对其文件系统访问进行虚拟化,它立刻就可以对 .tar 文件、老式磁带盘和只能通过虚拟专用网(VPN)访问的公司资源进行操作。供应商喜欢把这样的附件卖到数千美元。VFS 却免费提供了这样的功能。
或者说这几乎是免费的。程序员不用学习任何新知识;他们只需要像以往那样执行相同的 open、close 等文件系统操作。关键是所有的代码都和以前的一样。最大的困难就是当前支持成熟的 VFS 的语言运行时库很少。常见的困难之一是驱动程序通常是只读的,这或者是因为写功能需要进行更为复杂的编程,或者只是因为在类似 HTTP 这样的协议中没有定义写操作。
哪种语言具有 VFS 功能?
对 VFS 支持得最好的语言是 Tcl,ActiveState 的 Hobbs 擅长于这种语言。在其它语言(包括 Java 和 Perl)中,现有的 VFS 实现是“不纯的”,因为它们在实现中提供了新方法(比如 Perl 的 vfsopen)来补充核心库入口点。相比之下,在 Tcl 的发行版 8.4 中,正如有关 VFS 的社区页面所说明的那样:“Tcl 的文件系统是完全支持虚拟文件系统的”。尤其重要的是,这意味着在任何识别普通文件的地方,可以按语法规则使用虚拟文件资源。典型的 Tcl 允许:
image create -file myimage.gif
Tcl 8.4 将这一用法自然地扩展成:
image create -file ftp://myserver.com/myimage.gif
独立顾问 Matt Newman 首先在 20 世纪 90 年代末为 Tcl 实现了健壮的 VFS,以帮助他为某个大型金融企业所做的开发工作。在 2000 年底,Eurobios 科学家 Vince Darley 准备雄心勃勃地重新编写 Tcl 的文件系统应用程序编程接口(API),其中的优点之一就是提供 VFS 挂钩(hook)。
大多数在职的 Tcl 应用程序开发人员首先将 VFS 应用在上述的示例方面 - 例如灵活的支持 FTP 的编辑器。但值得注意的是,Tcl 的 VFS 先驱者(包括 Wippler,在前一篇有关应用程序部署的“服务器诊所(Server clinic)”专栏文章中曾提到过,请参阅参考资料)的初衷是开发“彻底的”VFS。也就是,不是使用 VFS 技术去访问现有的外部资源,而是要将一个特殊用途的数据库(位于应用程序内部)当作一个完整的文件系统进行管理。他们已经通过该机制显著地简化了应用程序开发和部署。从这个角度看,VFS 可以用来统一和整合不同的操作环境 - 开发、质保、客户站点,这样应用程序可以在所有操作环境中一致地操作。透明地将文件系统推广到外部文件,这只是附带的好处。清单 1 显示了两个摘自 Tcl 社区页面的代码示例,它们暗示了这个附带的好处的强大功能。
清单 1. 在 Tcl 中使用 VFS
package require vfs::urltype
vfs::urltype::Mount ftp
# With VFS activated, normal Tcl file commands
#
can copy files even to and from FTP servers.
file copy ftp://foo.bar.com/pub/Readme .
file copy myfile ftp://user:password@foo.bar.com/private.txt
package require vfs::zip
vfs::zip::Mount foo.zip foo.zip
# foo.zip is now part of the normal filesystem hierarchy.
cd foo.zip
# Within subdir1 on foo.zip, list all items.
set listing [glob -dir subdir1 *]
大多数语言都有访问 FTP 或 ZIP 的工具。从这个意义上说,VFS 类似于面向对象的高级语言或运行时库:它不提供任何新内容,您可以自己编程来做 VFS 可以做的任何事。但是,有了 VFS,资源管理就变得非常容易且更加合理。它不是个很难的概念;只是个很好的概念。
VFS 简化了许多有趣的问题。Tcl 程序员目前正在处理类似于下面这样的问题:
版本化的可动态装入库的集中压缩归档文件
智能网络代理程序
高级的“混合介质”备份管理器
我已经试验过“活动系统文件”的可编程性。可以把它们看作某些语言所支持的“特性”。特性是其访问会包括写操作副作用的属性:
result = thing.property
可能不只是从内存检索“property”的值,而有可能涉及这样的计算:在网络上传送数据、检查系统状态,等等。类似地,当我写:
file copy report.pdf backup
这不仅仅是将文件复制到目录中,而是要根据环境生成文件并执行其它操作。
面向特性的编程因其副作用较多,而被认为是“危险”的,基本上,用显式存取方法不能完成的操作,它也肯定完成不了。然而,它这种样式仍适合某些情形,而且我发现活动文件系统至少有时候要比它们所替代的 makefile 和脚本更容易编码。
结束语
Tcl 在其 VFS 成熟性方面要领先于其它语言;它已经解决了字符编码、I/O 体系结构和性能约束方面的难题,这些难题在其它语言社区中现在才刚开始显现。但是,您不一定非要使用 Tcl 才能应用 VFS 的思想。您自己的编程能从更为一致的访问类文件资源的方式中获益吗?大多数现代语言都提供了某种扩展内置构造的方法,因此可以用更一致和功能更强大的方式来编码 I/O。