UNIX 文件系统基本操作

本文示例源代码或素材下载
引言
Unix?中任何事物都是文件 的观点意味着,您将始终会与文件和目录打交道,无论您开发的是何种类型的应用程序 。任何事物都存储为文件,从数据到配置文件、甚至是设备,在对 UNIX 编程经过几个小时的学习之后,stdio.h 系统 Header 中的函数将能够为您提供很好的帮助 。
一个时常困扰 UNIX 编程新手的问题是,如何浏览一个目录,并对其中的文件、目录和符号链接进行相应的处理 。如何能够获取它们的列表,以及如何能够确定它们究竟是什么?
请继续阅读本文,以学习如何使用 dirent.h 函数系列 (opendir()/readdir()/closedir()) 来读取目录中的条目,以及使用 stat() 函数来确定这些条目所对应的内容 。
开始之前
本文中的示例代码(请参见下载)使用 C/C开发工具 (CDT) 在 Eclipse 3.1 中编写,readdir_demo 项目是一个托管的 Make 项目,该项目通过使用 CDT 程序生成规则构建 。您在这个项目中找不到 Makefile,但是它们非常简单,如果需要在 Eclipse 之外编译这些代码,您可以很容易地生成相应的 Makefile 。
如果您还没有尝试使用 Eclipse,那么您真的应该试一试 。它是一个非常好的集成开发环境 (IDE),并且随着发行版本的不断更新,它变得更加完善 。它来自于生命力顽强的 EMacS 以及基于 Makefile 的开发工具 。请参阅本文结尾处的参考资料部分,其中提供了一些很好的 Eclipse 文章的链接 。
读取目录条目
对于一个给定路径的目录,应该如何读取其中的条目呢?您无法像操作文件那样打开目录(使用 open() 或 fopen() 函数),并且即便可以这样做,所得到的数据可能是您正在使用的文件系统的专用格式,而对于不十分熟悉的程序员来说,直接访问这些数据将使情况变得更糟 。
dirent.h 函数,opendir()、readdir() 和 closedir(),它们正是您所需要的 。这些函数的使用与用来对文件进行操作的 open/read/close 的习惯用法非常相似,但有一点除外:对于每个目录条目,readdir() 函数一次返回一个指向特殊结构(struct dirent 类型)的指针 。通常,对目录进行浏览类似于清单 1 中所示的伪代码 。
清单 1. 读取目录中的内容
dir = opendir( "some/path/name" )
entry = readdir( dir )
while entry is not NULL:
do_something_with( entry )
entry = readdir( dir )
closedir( dir )
在出现问题时,opendir() 和 readdir() 函数都会返回 NULL,并且将设置全局变量 errno 的值,以指出所出现的错误 。如果 readdir() 返回 NULL,并且 errno 为 0(有时也称为 EOK 或 ENOERROR),则表示没有其他的目录条目 。
有一点需要注意,每个目录都包含“.(对该目录的引用)和“..(对该目录的父目录的引用)条目 。根据您所进行的操作,可能需要忽略对这些条目的处理 。
请注意,readdir() 不是线程安全的,因为所返回的结构是存储在函数库中的一个静态变量 。大多数现代的 Unix 系统都具有线程安全的 readdir_r(),如果您正在编写线程代码,可以使用这个函数作为替代 。
struct dirent 中包含了哪些内容呢?
POSIX 1003.1 标准仅仅为 struct dirent 定义了一个必需的条目,即 char 数组 d_name 。这是用标准的以 NULL 结尾的字符串表示的该条目的名称 。这个结构中任何其他内容都是特定于您的 UNIX 系统的 。
的确如此,struct dirent 中其他所有内容 都是不可移植的 。严格满足一致性的系统不应该在其中包含任何其他的内容 。如果您编写了使用额外结构成员的代码,那么您必须将其标记为不可移植的,并且包含一个完成相同任务的替换代码路径,如果您认为这样做特别友好的话 。

推荐阅读