13.2.4 目录操作
新建目录操作可使用函数mkdir()实现,该函数的一般形式是:
mkdir(路径, umask)
当目录被成功创建函数的返回值为0,否则为–1。
获得当前子目录的操作可使用函数getcwd(),该函数的一般形式是:
getcwd(char *buf, size_t size);
其中,*buf是存放当前目录的缓冲区,size是缓冲区的大小。如果函数返回当前目录的字符串长度超过size规定的大小,它将返回NULL。
执行程序的工作目录就是当前子目录,如果要改变执行程序的工作目录,可以使用函数chdir()。这个函数的作用如同shell里的cd命令一样,它的一般形式是:
chdir(路径);
另一个常用目录操作是扫描子目录,与此相关的函数被封装在头文件dirent.h里。它们使用一个名为DIR的结构作为子目录处理的基础,这个结构的指针所指向的内存空间被称之为子目录流。与子目录流操作相关的函数如表13.7所示。
表13.7 子目录流操作相关函数
函 数 名 | 说 明 |
DIR *opendir(const char *name); | 打开路径并建立子目录流,返回子目录流指针 |
struct dirent *readdir(DIR *dirp); | 函数返回一个指针,指针指向的结构里保存着子目录流dirp中下一个目录数据项的有关资料。后续的readdir调用将返回后续的目录数据。如果错误或到达子目录尾,将返回NULL值 |
long int telldir(DIR *dirp); | 函数返回值里记录着子目录流里的当前位置 |
void seekdir(DIR *dirp, long int loc); | 对dirp指定的子目录流中的目录数据项的指针进行设置。loc的值用来设置指针位置,它应该通过前一个telldir调用获得 |
int closedir(DIR *dirp); | 关闭子目录流,返回关闭操作结果 |
下例将设计一个可遍历子目录中所有文件的函数,用于演示目录操作及目录流操作相关函数的使用方法。代码如下:
#include <fcntl.h> // 提供open()函数
#include <unistd.h>
#include <stdio.h>
#include <dirent.h> // 提供目录流操作函数
#include <string.h>
#include <sys/stat.h> // 提供属性操作函数
#include <sys/types.h> // 提供mode_t类型
#include <stdlib.h>
void scan_dir(char *dir, int depth) // 定义目录扫描函数
{
DIR *dp; // 定义子目录流指针
struct dirent *entry; // 定义dirent结构指针保存后续目录
struct stat statbuf; // 定义statbuf结构保存文件属性
if((dp = opendir(dir)) == NULL) { // 打开目录,获得子目录流指针,判断操作
// 是否成功
puts("无法打开该目录");
return;
}
chdir(dir); // 切换到当前目录中去
while((entry = readdir(dp)) != NULL) { // 获取下一级目录信息,如果未结
// 束则循环
lstat(entry->d_name, &statbuf); // 获取下一级成员属性
if(S_IFDIR & statbuf.st_mode) { // 判断下一级成员是否是目录
if(strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)
continue; // 如果获得的成员是符号“.”和“..”,
// 跳过本次循环
printf("%*s%s//n",depth,"",entry->d_name); // 输出目录名称
scan_dir(entry->d_name,depth+4);// 递归调用自身,扫描下一级目录的内容
}
else
printf("%*s%s/n", depth, "", entry->d_name); // 输出属性不是目录
// 的成员
}
chdir(".."); // 回到上一级目录
closedir(dp); // 关闭子目录流
}
该函数的作用是遍历目录,将其所有的子目录和文件输出到终端上。遍历子目录实现的方法是递归调用,首先判断子目录流指针所指向的文件是否为目录文件。如果是,该函数将调用自身去遍历子目录;如果不是,则输出文件名称,继续遍历当前目录,直到子目录流指向NULL。函数的depth参数作用是在子目录前增加空格的数量,每一轮递归都将增加4个空格,这样能更容易的显示出目录的层次。下面设计一个小程序进行遍历目录。
int main()
{
puts("扫描/boot目录:");
scan_dir("/boot",0); // 调用目录扫描函数
puts("扫描结束"); // 扫描结束时输出提示信息
return 0;
}
程序中通过调用scan_dir()函数遍历“/boot”目录,程序的输出结果如下(有删节):
扫描/boot目录:
System.map-2.6.27.15-170.2.24.fc10.i686
config-2.6.27.12-170.2.5.fc10.i686
grub/
ufs2_stage1_5
stage1
…
System.map-2.6.27.12-170.2.5.fc10.i686
config-2.6.27.9-159.fc10.i686
…
efi/
EFI/
redhat/
grub.efi
initrd-2.6.27.15-170.2.24.fc10.i686.img
vmlinuz-2.6.27.15-170.2.24.fc10.i686
…
扫描结束