Linux DIR,dirent,stat结构体

1、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,是一个内部结构,以下几个函数用这个内部结构保存当前正在被读取的目录的有关信息。
函数 DIR *opendir(const char *pathname),即打开文件目录,返回的就是指向DIR结构体的指针,而该指针由以下几个函数使用:

struct dirent *readdir(DIR *dp);   
  
void rewinddir(DIR *dp);   
  
int closedir(DIR *dp);   
  
long telldir(DIR *dp);   
  
void seekdir(DIR *dp,long loc);  

2、dirent

首先我们要弄清楚目录文件(directory file)的概念:这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针。
从定义能够看出,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函数了。

3、fstat、stat和lstat

stat系统调用系列包括了fstat、stat和lstat,它们都是用来返回“相关文件状态信息”的,三者的不同之处在于设定源文件的方式不同。
struct stat结构体

在struct stat结构体中我们常用的且各个平台都一定有的域。

st_mode 文件权限和文件类型信息 
st_ino   与该文件关联的inode
st_dev   保存文件的设备
st_uid   文件属主的UID号
st_gid   文件属主的GID号
st_atime 文件上一次被访问的时间
st_ctime 文件的权限、属主、组或内容上一次被修改的时间
st_mtime 文件的内容上一次被修改的时间。(和st_ctime的不同之处显而易见)
st_nlink  该文件上硬连接的个数

在Linux中stat定义为:

struct stat { 
    dev_t         st_dev;       //文件的设备编号 
    ino_t         st_ino;       //节点 
    mode_t        **st_mode**;      //文件的类型和存取的权限 
    nlink_t       st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1 
    uid_t         st_uid;       //用户ID 
    gid_t         st_gid;       //组ID 
    dev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号 
    off_t         st_size;      //文件字节数(文件大小) 
    unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小) 
    unsigned long st_blocks;    //块数 
    time_t        st_atime;     //最后一次访问时间 
    time_t        st_mtime;     //最后一次修改时间 
    time_t        st_ctime;     //最后一次改变时间(指属性) 
}; 

st_mode处这个域不像其他域那么容易使用,其他的域的值显而易见,而st_mode域是需要一些宏予以配合才能使用的。
其实,通俗说,这些宏就是一些特定位置为1的二进制数的外号,我们使用它们和st_mode进行”&”操作,从而就可以得到某些特定的信息。
st_mode 定义了下列数种情况:

    S_IFMT   0170000                  文件类型的位遮罩 
    S_IFSOCK 0140000              scoket 
    S_IFLNK 0120000                 符号连接 
    S_IFREG 0100000                一般文件 
    S_IFBLK 0060000                 区块装置 
    S_IFDIR 0040000                 目录 
    S_IFCHR 0020000               字符装置 
    S_IFIFO 0010000                  先进先出 
    S_ISUID 04000                              文件的(set user-id on execution)位 
    S_ISGID 02000                              文件的(set group-id on execution)位 
    S_ISVTX 01000                               文件的sticky位 
    S_IRUSR(S_IREAD) 00400        文件所有者具可读取权限 
    S_IWUSR(S_IWRITE)00200      文件所有者具可写入权限 
    S_IXUSR(S_IEXEC) 00100         文件所有者具可执行权限 
    S_IRGRP 00040             用户组具可读取权限 
    S_IWGRP 00020             用户组具可写入权限 
    S_IXGRP 00010             用户组具可执行权限 
    S_IROTH 00004             其他用户具可读取权限 
    S_IWOTH 00002             其他用户具可写入权限 
    S_IXOTH 00001             其他用户具可执行权限 

stat函数:
表头文件:

#include <sys/stat.h> 
#include <unistd.h>

定义函数:

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

函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno
错误代码:

    ENOENT         参数file_name指定的文件不存在 
    ENOTDIR        路径中的目录存在但却非真正的目录 
    ELOOP          欲打开的文件有过多符号连接问题,上限为16符号连接 
    EFAULT         参数buf为无效指针,指向无法存在的内存空间 
    EACCESS        存取文件时被拒绝 
    ENOMEM         核心内存不足 
    ENAMETOOLONG   参数file_name的路径名称太长 

例子:

#include <sys/stat.h> 
#include <unistd.h> 
#include <stdio.h> 
int main() { 
    struct stat buf; 
    stat("/etc/hosts", &buf); 
    printf("/etc/hosts file size = %d\n", buf.st_size); 
} 

fstat、stat和lstat的区别:

int fstat(int filedes, struct stat *buf);
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);

fstat区别于另外两个系统调用的地方在于,fstat系统调用接受的是 一个“文件描述符”,而另外两个则直接接受“文件全路径”。
文件描述符是需要我们用open系统调用后才能得到的,而文件全路经直接写就可以了。
stat和lstat的区别:当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;而stat返回的是该链接指向的文件的信息。
(lstat比stat多了一个l,因此它是有本事处理符号链接文件的,因此当遇到符号链接文件时,lstat当然不会放过。而 stat系统调用没有这个本事,它只能对符号链接文件睁一只眼闭一只眼,直接去处理链接所指文件喽)

最后,总结一下,想要获取某目录下(比如a目下)b文件的详细信息,我们应该怎样做?
首先,我们使用opendir函数打开目录a,返回指向目录a的DIR结构体c。
接着,我们调用readdir( c)函数读取目录a下所有文件(包括目录),返回指向目录a下所有文件的dirent结构体d。
然后,我们遍历d,调用stat(d->name,stat *e)来获取每个文件的详细信息,存储在stat结构体e中。

上一篇:kuangbin带你飞 专题十五 数位DP


下一篇:leetcode-1494-并行课程