|
打开、读取、关闭普通文件可以使用open()、read()、close()来实现相对应的操作,目录文件也有类似的函数来实现这些功能,如opendir()、readdir()和 closedir()。下面就一一来介绍一下这些函数。 opendir用于访问和读取读取目录内容。 1.头文件 #include <sys/types.h> #include <dirent.h> 2.函数原型 DIR *opendir(const char *name); 3.参数 name:要打开的目录的路径。这个路径可以是相对路径或绝对路径。 4.返回值 成功:返回指向 DIR 结构体的指针,该指针用于进一步操作该目录(如读取目录项)。 失败:返回 NULL,可以通过 errno 获取错误信息。 readdir1.头文件 #include <dirent.h> 2.函数原型 struct dirent *readdir(DIR *dirp); 3.参数 dirp:指向由 opendir() 返回的 DIR 结构体的指针,用于表示打开的目录流。 4.返回值 成功:返回指向 dirent 结构体的指针,该结构体包含目录项的信息。 结束或错误:当目录项读取完毕或发生错误时,返回 NULL。通常,readdir 返回 NULL 表示目录读取结束,或者遇到错误时可以通过 errno 获取更多信息。 注: 流是抽象的一个数据通道,目录流(DIR 类型的对象)是一个表示打开目录的抽象数据通道。通过这个流,我们可以按顺序读取目录中的每一个条目。 下面就来介绍一下struct dirent结构体: struct dirent { ino_t d_ino; /* Inode 编号 */ off_t d_off; /* Not an offset; see below */ 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]; /* 文件名 */ }; 在这个结构体中,需要重点关注的是d_ino和d_name这两个字段即可,其余的字段一般是用不上,所以不用重点关注。 每调用一次readdir函数,就会从drip所指向的目录有中读取下一条目录项,并返回一个struct dirent结构体指针,指向经静态分配而得的 struct dirent 类型结构,每次调用 readdir()都会覆盖该结构。一旦遇到目录结尾或是出错,readdir()将返回 NULL,针对后一种情况,还会设置 errno 以示具体错误。 这时就有问题了,什么时候是指向了目录的末尾,什么时候是出错了呢?以下给出代码参考进行判断: struct dirent *entry; // 读取目录项 while ((entry = readdir(dir)) != NULL) { // 打印目录项名称 printf("Name: %s\n", entry->d_name); } // 检查是否有读取错误 if (errno != 0) { perror("readdir"); closedir(dir); return EXIT_FAILURE; } |
需要注意的是,在使用readdir()函数时,返回的内容并非是使用文件名进行排序的,而是取决于文件系统向该目录添加文件时所遵循的顺序,和在文件被删除以后对目录列表中空隙的填补方式进行排序。 closedir用于关闭目录流的函数。 1.头文件 #include <sys/types.h> #include <dirent.h> 2.函数原型 int closedir(DIR *dirp); 3.参数 dirp: 指向 DIR 结构的指针,该结构由 opendir() 返回。它表示要关闭的目录流。 4.返回值 成功: 返回 0。失败: 返回 -1,并设置 errno 以指示错误类型。 5.示例:(打开目录,并查看目录中的文件) #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <dirent.h> #include <errno.h> #include <unistd.h> int main(){ const char *dir_path = "directory"; struct stat statbuf; DIR *dir; struct dirent *entry; int file_count=0; printf("File name:%s\n", dir_path); if (stat(dir_path, &statbuf) == -1) { perror("stat"); return 1; } if (S_ISDIR(statbuf.st_mode)) { printf("It's the directory: YES\n"); } else { printf("It's the directory: NO\n"); } dir = opendir(dir_path); if (dir == NULL) { perror("opendir"); return 1; } printf("Directory Contents:\n"); while ((entry = readdir(dir)) != NULL) { printf("\t%s\t%ld\n",entry->d_name,entry->d_ino); file_count ++; if (file_count == 3) { printf("Resetting directory stream...\n"); rewinddir(dir); } } if (errno != 0) { perror("readdir"); closedir(dir); return EXIT_FAILURE; } closedir(dir); return 0; } |
接下来需要自行创建directory文件夹,下图是directory文件夹结构: $ tree directory/ directory/ ├── 1 ├── 2 ├── 3 ├── 4.txt ├── 5.txt └── 6.txt 3 directories, 3 files |
6.查看执行结果 File name:directory It's the directory: YES Directory Contents: 1 5255834 3 5255836 6.txt 5255839 Resetting directory stream... 1 5255834 3 5255836 6.txt 5255839 .. 5255821 5.txt 5255838 2 5255835 4.txt 5255837 . 5255833 |
可以看到,首先打印出来要检查的directory文件名,之后检查directory文件为文件夹,在之后开始打印文件夹中的内容,当DIR 结构体的指针指向第三个文件后,使用rewinddir()函数重置目录流,直到打印完毕directory文件夹中的内容。同时我们也看到文件并不是按规律打印出来的,也印证了前面介绍的文件存储顺序取决于文件系统向该目录添加文件时所遵循的顺序,和在文件被删除以后对目录列表中空隙的填补方式,并不是使用ls命令查看到的有序排列的顺序。
|