现在的位置: 首页 > 综合 > 正文

扫描目录

2019年08月09日 ⁄ 综合 ⁄ 共 2215字 ⁄ 字号 评论关闭

3.8  扫描目录

Linux系统上一个常见问题就是对目录进行扫描,也就是确定一个特定目录下存放的文件。在shell程序设计中,这很容易做到——只需让shell做一次表达式的通配符扩展。过去,UNIX操作系统的各种变体都允许用户通过编程访问底层文件系统结构。我们仍然可以把目录当作一个普通文件那样打开,并直接读取目录数据项,但不同的文件系统结构及其实现方法已经使这种办法没什么可移植性了。现在,一整套标准的库函数已经被开发出来,使得目录的扫描工作变得简单多了。

与目录操作有关的函数在dirent.h头文件中声明。它们把一个名为DIR的结构作为目录操作的基础。被称为“目录流”的指向这个结构的指针(DIR *)被用来完成各种目录操作,其使用方法与文件流(FILE *)非常相似。目录数据项本身在dirent结构中返回,该结构也是在dirent.h头文件里声明的,用户绝不要直接改动DIR结构中的数据字段。

我们将介绍下面这几个函数:

l opendir、closedir

l readdir

l telldir

l seekdir

3.8.1  opendir函数

opendir函数的作用是打开一个目录并建立一个目录流。如果成功,它返回一个指向DIR结构的指针,该指针用于读取目录数据项。

opendir在失败时会返回一个空指针。注意,目录流用一个底层文件描述符来访问目录本身,所以如果打开的文件过多,opendir可能会失败。

3.8.2  readdir函数

readdir函数将返回一个指针,指针指向的结构里保存着目录流drip中下一个目录项的有关资料。后续的readdir调用将返回后续的目录项。如果发生错误或者到达目录尾,readdir将返回NULL。POSIX兼容的系统在到达目录尾时会返回NULL,但并不改变errno的值,在发生错误时才会设置errno。

注意,如果在readdir函数扫描目录的同时还有其他进程在该目录里创建或删除文件,readdir将不保证能够列出该目录里的所有文件(和子目录)。

dirent结构中包含的目录数据项内容包括以下部分:

l ino_t d_ino——文件的inode节点号。

l char d_name[]——文件的名字。

要想进一步了解目录中某个文件的详细资料,则需要使用在本章前面介绍过的stat调用。

3.8.3  telldir函数

telldir函数的返回值记录着一个目录流里的当前位置。你可以在随后的seekdir调用中利用这个值来重置目录扫描到当前位置。

3.8.4  seekdir函数

seekdir函数的作用是设置目录流dirp的目录项指针。loc的值用来设置指针位置,它应该通过前一个telldir调用获得。

3.8.5  closedir函数

closedir函数关闭一个目录流并释放与之关联的资源。它在执行成功时返同0,发生错误时返回-1。

在下面的printdir.c程序中,我们把许多文件处理函数集中在一起实现一个简单的目录列表功能。目录中的每个文件单独列在一行上。每个子目录会在它的名字后面加上一个斜线字符/,子目录中的文件在缩进四个空格后依次排列。

程序会逐个切换到每个下级子目录里,这样使它找到的文件都有一个可用的名字,也就是说,它们都可以被直接传递到opendir函数里去。如果目录的嵌套结构太深,程序执行就会失败,因为对允许打开的目录流数目是有限制的。

我们当然可以采取一个更通用的做法,让程序能够通过一个命令行参数来指定起点(从哪个目录开始)。请查阅有关工具程序(如ls和find)的Linux源代码来找到实现更通用程序的方法。

实验:一个目录扫描程序

(1) 程序的开始是一些必要的头文件。接下来是printdir函数,它的作用是输出当前目录的内容。它将递归遍历各级子目录,使用depth参数来控制缩排。

(2) 下面我们来看main函数:

这个程序的输出结果如下所示(经过简化):

实验解析

绝大部分操作都是在printdir函数里完成的,所以我们重点对它进行说明。在用opendir函数检查完指定目录是否存在后,printdir调用chdir进入指定目录。如果readdir函数返回的数据项不为空,程序就检查该数据项是否是一个目录。如果不是,程序就根据depth的值缩进打印文件数据项的内容。

如果该数据项是一个目录,我们就需要对它进行递归遍历。在跳过.和..数据项(它们分别代表当前目录和上一级目录)后,printdir函数调用自己并再次进入一个同样的处理过程。那它又是如何退出这些循环的呢?一旦while循环完成,chdir(“. . ”)调用把它带回到目录树的上一级,从而可以继续列出上级目录中的清单。调用closedir(dp)关闭目录以确保打开的目录流数目不超出其需要。

作为第4章对Linux环境进行讨论的引子,我们来看看一个能够使这个程序更具通用性的方法。这个程序的功能受限是因为它只能对目录/home/neil进行操作。如果我们按下面的方法对main进行修改,就能把它变成一个更有用的目录浏览器:

我们修改了三条语句,增加了五条语句,它现在是一个通用的工具程序了。它现在多了一个目录名的可选参数,其默认值是当前目录。你可以通过下面的命令运行它:

输出结果将分页显示,用户可以通过翻页查看其输出。可以说,用户现在有了一个非常方便、通用的目录树浏览器。再努把力,你还可以增加显示文件的空间占用情况、限制遍历显示的深度等其他功能。

抱歉!评论已关闭.