struct dirent详解

发布时间:2023-05-20

一、什么是struct dirent

struct dirent(directory entry)是Unix/Linux系统中用来描述目录项的结构体,应用程序通过调用操作系统提供的readdir()函数读取目录中的文件和子目录,并通过struct dirent结构体来描述它们。

struct dirent {
    ino_t          d_ino;       /* Inode number */
    off_t          d_off;       /* Not an offset; see below */
    unsigned short d_reclen;    /* Length of this record */
    unsigned char  d_type;      /* Type of file; one of the DT_XXX constants */
    char           d_name[256]; /* Null-terminated filename */
};

struct dirent结构体中包含五个成员变量,分别是: d_ino:文件或目录的inode节点号; d_off:目录项在目录文件中的偏移量。在Linux中,当应用程序读取目录时,d_off被设置为下一个目录项的偏移量(即读完当前目录项后,下一个读取的目录项的偏移量为d_off); d_reclen:这个目录项的长度。在多数文件系统中,这个值等于d_name的长度加上些许的额外控制信息长度; d_type:描述目录项所指向的文件类型(文件类型的定义和取值是系统相关的); d_name:目录项所指向的文件或目录的名字,是一个字符串数组,不同系统有不同的d_name长度上限,常用的是256字节。

二、如何使用struct dirent

使用struct dirent需要先打开目录,并调用readdir()函数来获取目录中的文件和子目录信息。 示例代码如下:

DIR *dir;
struct dirent *ent;
dir = opendir("/path/to/dir");
while ((ent = readdir (dir)) != NULL) {
    printf ("%sn", ent->d_name);
}
closedir(dir);

上面代码中,opendir()函数打开目录并返回一个目录流指针,readdir()函数读取目录中的文件和子目录信息并返回一个指向struct dirent的指针,使用指针ent->d_name获取目录项的名字。

三、注意事项

在使用struct dirent时,有一些需要注意的事项:

  1. d_name字段长为256个字节,但不同的文件系统有不同的限制,有些文件系统可能会把文件名缩短到12到14个字符长度,以便把额外的文件信息同时存储在磁盘中。
  2. d_type字段可能会被设置成一些系统特定的值,而这些值的定义也会随着系统版本的更新而发生改变,所以如果要编写可移植的程序,就需要避免使用d_type字段。
  3. readdir()读取目录项时,每读取一次就会返回下一个目录项,直到读取完了目录中的所有项,如果想要重复读取,就要关闭目录流并再次打开。

四、示例代码

下面展示一个遍历目录中所有文件和子目录的示例代码:

void traverseDir(char *basePath) {
    DIR *dir;
    struct dirent *entry;
    if ((dir = opendir(basePath)) == NULL) {
        fprintf(stderr, "Cannot open directory:%sn",basePath);
        return;
    }
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        printf("%s/%sn", basePath, entry->d_name);
        if (entry->d_type == DT_DIR) {
            char path[1000];
            sprintf(path, "%s/%s", basePath, entry->d_name);
            traverseDir(path);
        }
    }
    closedir(dir);
}
int main() {
    traverseDir("/path/to/dir");
    return 0;
}

第一个while循环遍历目录下的所有文件和子目录,并打印文件和子目录的名字。 第二个if语句判断,如果当前目录项名字为"."或"..",则跳过该项,否则继续遍历该目录项。 第二个if语句判断如果当前目录项是子目录,则递归遍历该子目录。

五、总结

struct dirent提供了Unix/Linux系统下操作目录和文件的基本结构体,通过readdir()函数读取目录中的文件和子目录,并通过struct dirent结构体来描述它们,使用该结构体可以完成对目录的遍历等操作。