Linux下DIR,dirent,stat等结构体详解

Linux下DIR,dirent,stat等结构体详解

DIR结构体的定义:

struct __dirstream
   {
    void *__fd;
    char *__data;
    int __entry_data;
    char *__ptr;
    int __entry_ptr;
    size_t __allocation;
    size_t __size;
    __libc_lock_define (, __lock)
   };
typedef struct __dirstream DIR;

DIR结构体类似于FILE,是一个内部结构,以下几个函数用这个内部结构保存当前正在被读取的目录的有关信息(摘自《UNIX环境高级编程(第二版)》)。函数 DIR opendir(const char pathname),即打开文件目录,返回的就是指向DIR结构体的指针,而该指针由以下几个函数使用:

1 struct dirent *readdir(DIR *dp);
2 void rewinddir(DIR *dp);
3 int closedir(DIR *dp);
4 long telldir(DIR *dp);
5 void seekdir(DIR *dp,long loc);

关于DIR结构,我们知道这么多就可以了,没必要去再去研究他的结构成员。

接着是dirent结构体,首先我们要弄清楚目录文件(directory file)的概念:这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针(摘自《UNIX环境高级编程(第二版)》)。从定义能够看出,dirent不仅仅指向目录,还指向目录中的具体文件,readdir函数同样也读取目录下的文件,这就是证据。以下为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结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似ls -l那种效果的文件信息,必须要靠stat函数了。

通过readdir函数读取到的文件名存储在结构体dirent的d_name成员中,而函数

int stat(const char file_name, struct stat buf);

的作用就是获取文件名为d_name的文件的详细信息,存储在stat结构体中。以下为stat结构体的定义:

struct stat {
        mode_t     st_mode;       //文件访问权限
        ino_t      st_ino;       //索引节点号
        dev_t      st_dev;        //文件使用的设备号
        dev_t      st_rdev;       //设备文件的设备号
        nlink_t    st_nlink;      //文件的硬连接数
        uid_t      st_uid;        //所有者用户识别号
        gid_t      st_gid;        //组识别号
        off_t      st_size;       //以字节为单位的文件容量
        time_t     st_atime;      //最后一次访问该文件的时间
        time_t     st_mtime;      //最后一次修改该文件的时间
        time_t     st_ctime;      //最后一次改变该文件状态的时间
        blksize_t st_blksize;    //包含该文件的磁盘块的大小
        blkcnt_t   st_blocks;     //该文件所占的磁盘块
      };

这个记录的信息就很详细了吧,呵呵。

最后,总结一下,想要获取某目录下(比如a目下)b文件的详细信息,我们应该怎样做?

首先,我们使用opendir函数打开目录a,返回指向目录a的DIR结构体c。

接着,我们调用readdir( c)函数读取目录a下所有文件(包括目录),返回指向目录a下所有文件的dirent结构体d。

然后,我们遍历d,调用stat(d->name,stat *e)来获取每个文件的详细信息,存储在stat结构体e中。

总体就是这样一种逐步细化的过程,在这一过程中,三种结构体扮演着不同的角色。

d_type表示档案类型:

enum
{
    DT_UNKNOWN = 0,         //未知类型
# define DT_UNKNOWN DT_UNKNOWN
    DT_FIFO = 1,            //管道
# define DT_FIFO DT_FIFO
    DT_CHR = 2,             //字符设备
# define DT_CHR DT_CHR
    DT_DIR = 4,             //目录
# define DT_DIR DT_DIR
    DT_BLK = 6,             //块设备
# define DT_BLK DT_BLK
    DT_REG = 8,             //常规文件
# define DT_REG DT_REG
    DT_LNK = 10,            //符号链接
# define DT_LNK DT_LNK
    DT_SOCK = 12,           //套接字
# define DT_SOCK DT_SOCK
    DT_WHT = 14             //链接
# define DT_WHT DT_WHT
};

普通文件,目录文件,块特殊文件,字符特殊文件,套接字,FIFO,符号链接. 文件类型信息包含在stat结构的st_mode成员中,可以用如下的宏确定文件类型,这些宏是stat结构中的 st_mode成员.

S_ISREG();S_ISDIR();S_ISCHR();S_ISBLK();S_ISFIFO();S_ISLNK();S_ISSOCK()
struct stat buf;
char * ptr;
if(lstat(argv,&buf)<0)
if (S_ISREG(buf.st_mode))
ptr="普通文件";
if (S_ISDIR(buf.st_mode))
ptr="目录";

代码:

#include <stdio.h>
#include <dirent.h>
#include <string>

using namespace std;

int main(int argc,char *argv[])
{
    DIR * dp;
    struct dirent *_dirrent;
    string path = "/home/amzing/c++";
    dp = opendir(path.c_str());
    if (!dp)
    {
        printf("open directory error\n");
        return 0;
    }

    while (_dirrent = readdir(dp))
    {

        printf("_dirrent->d_name %s\n", _dirrent->d_name);
        printf("_dirrent->d_type %d\n", _dirrent->d_type);
    }
    closedir(dp);
    return 0;
}
#include <stdio.h>
#include <dirent.h>
#include <string>
#include <sys/stat.h>
#include <iostream>

using namespace std;

int get_FileType(string path)
{
    struct stat _stat;
    int ret = lstat(path.c_str(), &_stat);
    if(ret<0)return -1;
    return _stat.st_mode;
}


int main(int argc,char *argv[])
{
    string path = "/home/amzing/c++";
    int file_type = get_FileType(path);
    if(file_type<0)
    {
        cout<<"path wrong!"<<endl;
    }
    else
    {
        if (S_ISDIR(file_type))
        {
            cout<<path<<" is a folder"<<endl;
        }
        else
        {
            cout<<path<<" is a file"<<endl;
        }
    }
    return 0;
}
文章目录