24-与目录有关的函数-读取目录

这一篇将非常重要,这里介绍的函数可以帮助我们通过写程序来遍历目录。需要重点掌握 4 个函数 opendir、readdir、rewinddir 和 closedir。其实还有两个不怎么重要的函数 seekdir 和 telldir,它似乎没有太大用处,而且很少能用上,感兴趣的同学可以自己查阅 man 手册。

这些函数都是 glibc 提供的函数,也就是说它们并不是系统调用。在学习它们的时候,我们应该拿它和 标准 IO 库中的文件操作的相关函数进行类比(fopen、fread、rewind、fclose、fseek、ftell)。可以说,你几乎不用学习就可以掌握目录操作相关的一系列函数了。

1 opendir

  • 函数原型
DIR *opendir(const char *name);

这里的 DIR* 就类似于标准 IO 中的 fopen 函数返回的 FILE*。时刻要提醒自己,目录也是文件。

2 readdir

  • 函数原型
struct dirent *readdir(DIR *dirp);

readdir 函数将从当前的目录项偏移的位置开始,读取一条目录项,同时将偏移量增加到下一目录项的位置。

它的返回值 dirent 这个结构体看起来很陌生,如果你是一路读着博文过来,相信你一定能回忆起前面所述的 dir_entry 结构体,它简直无比重要,我已经提及数次。所以无论如何,你也要回头把文件系统相关的知识复习一遍。

只不过 dirent 是在 glibc 中被重新定义,还加入了一个新的字段 d_off 目录项偏移。做了新的一层封装是 glibc 喜欢干的事,它只是帮助我们屏蔽操作系统相关的细节,这一点就像标准IO库中的 fopen、fread 等函数一样。

struct dirent {
    ino_t          d_ino;       // inode number
    off_t          d_off;       // not an offset; see NOTES
    unsigned short d_reclen;    // length of this record
    unsigned char  d_type;      // type of file; not supported by all filesystem types */
    char           d_name[256]; // filename
};

3 实验——遍历目录

这段代码实现一个非常简单的功能,就是打印某个目录下所有的目录项(也就是 dir_entry).

  • 代码
// traversaldir.c
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <stdio.h>

void traversal(DIR* dir) {
  struct dirent* de = NULL;
  while((de = readdir(dir)) != NULL) {
    printf("%ld\t0x%02x\t%ld\t%s\n", de->d_ino, de->d_type, de->d_off, de->d_name);
  }
}

int main(int argc, char* argv[]) {
  DIR* dp = opendir(argv[1]);
  if (!dp) {
    perror("opendir");
    return -1; 
  }
  traversal(dp);
  closedir(dp);
}
  • 编译
$ gcc traversaldir.c -o traversaldir
  • 运行
// 遍历当前目录
$ ./traversaldir ./

打印的结果如下(inode 编号、文件类型、偏移量、文件名):

1048944 0x08    65321313        mychdir.c
1050210 0x08    494841770       mymkdir.c
1053420 0x08    724501007       traversaldir.c
1053428 0x08    725159058       myrmdir.c
1050187 0x04    732171668       testdir
1053440 0x08    909641663       traversaldir
1048943 0x04    997909376       .
1050194 0x04    1253739340      ..
1053429 0x08    1569584421      mymkdir
1053421 0x0a    1628563748      hellotest
1053425 0x08    1934677973      mychdir
1053436 0x08    2147483647      myrmdir

实际上我的这个目录现状如下:

drwxrwxr-x  3 allen allen 4096 124 20:41 ./
drwxrwxr-x 10 allen allen 4096 123 12:46 ../
lrwxrwxrwx  1 allen allen    8 124 20:39 hellotest -> testdir//
-rwxrwxr-x  1 allen allen 7460 123 12:42 mychdir*
-rw-rw-r--  1 allen allen  199 123 12:42 mychdir.c
-rwxrwxr-x  1 allen allen 7384 124 18:02 mymkdir*
-rw-rw-r--  1 allen allen  203 124 18:02 mymkdir.c
-rwxrwxr-x  1 allen allen 7384 123 22:34 myrmdir*
-rw-rw-r--  1 allen allen  152 123 22:34 myrmdir.c
drwxrwxr-x  2 allen allen 4096 124 21:15 testdir/
-rwxrwxr-x  1 allen allen 7536 124 20:41 traversaldir*
-rw-rw-r--  1 allen allen  410 124 20:41 traversaldir.c

4 总结

  • 目录也是文件(请原谅我无休止的重复这个知识点)
  • 目录文件中是一个个的 dir_entry 结构体
  • opendir 函数就像 fopen 函数
  • 掌握opendir 和 readdir 函数
  • 掌握 rewinddir 函数,虽然本文并未演示,但它很简单,不是吗?
  • 记住 closedir

这里留下一个小小的练习:

请递归列出目录下的所有文件,有点类似 ll -R 命令。

这个题目并不容易,你需要考虑可能因为软链接引起的循环。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值