在Linux系统中我们需要在一个特定目录下对该目录下所有的文件以及目录(文件夹)进行便利访问。
Linux获取目录文件的流程如下:
1.打开指定目录,使用opendir得到目录句柄。
2.while循环中使用readdir获取目录的内容,并存储到struct dirent 结构体变量中。
3.dirent结构体变量存储了文件/文件夹的一些属性,可以通过这些属性进行一些差异化操作。
4.最后关闭目录句柄closedir。
函数原型与结构体
opendir原型:
DIR *opendir(const char *path);
返回值:NULL 打开目录失败
readdir原型:
struct dirent *dir_entry; //存储获取的目录内容
struct dirent *readdir(DIR *dirp);
返回值:NULL说明获取目录内容失败或者目录内容已经全部读取完成 ;
closedir原型:
int closedir(DIR *dirp);
返回值:0正常 -1错误
需要头文件<sys/stat.h>,<dirent.h>
dirent结构体内容:
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */
}
dirent结构体常用的三个变量是d_reclen,d_type,d_name。
d_reclen 表示的是文件名长度,6表示子目录或以.开头的隐藏文件,24表示普通文本文件,28为二进制文件,32表示文件夹。
d_type 表示的是当前的类型,该值为4说明这是一个文件夹,该值为8说明这是一个文件。
d_name 表示的是当前文件/文件夹的名称。
DIR 结构体内容:
struct __dirstream
{
void *__fd; /* `struct hurd_fd' pointer for descriptor. */
char *__data; /* Directory block. */
int __entry_data; /* Entry number `__data' corresponds to. */
char *__ptr; /* Current pointer into the block. */
int __entry_ptr; /* Entry number `__ptr' corresponds to. */
size_t __allocation; /* Space allocated for the block. */
size_t __size; /* Total valid data in the block. */
__libc_lock_define (, __lock) /* Mutex lock for this structure. */
};
typedef struct __dirstream DIR;
DIR结构体的内容不太需要关注。
例程
给定一个路径,去遍历路径下的有效文件:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/types.h>
void getDir(){
//传入一个有效路径
std::string path = "/Users/fileTest";
struct stat sb;
//判断该路径是否是目录
if(stat(path.c_str(),&sb)!=0||!S_ISDIR(sb.st_mode)){
return;
}
struct dirent* ent = nullptr;
DIR *pDir = nullptr;
pDir = opendir(path.c_str());
while (nullptr != (ent=readdir(pDir))) {
//文件夹里默认存在.和..,直接跳过
if(strcmp(ent->d_name,".")==0||strcmp(ent->d_name,"..")==0) continue;
//如果是一个文件夹
if (ent->d_reclen == 32) {
std::cout<<"folder:"<<ent->d_name<<std::endl;
}else{//如果是一个文件
std::cout<<"file:"<<ent->d_name<<std::endl;
}
}
closedir(pDir);
}
int main(int argc, const char * argv[]) {
// insert code here...
getDir();
return 0;
}
需要注意的一个点是,.和..是在Unix 以及所有类unix系统中,在文件夹中默认生成的,.表示当前文件夹,..表示当前文件夹的父文件夹。通常我们是不需要两个隐藏文件夹的,因此在遍历的时候直接跳过了。
此外,传入一个路径的时候我们需要判断该路径是否是一个合法目录,因此需要额外判断。