• linux 之文件基础 (五)、文件属性


    简介

    当我们使用 ls -al 指令时,终端将打印文件的属性信息。那么,在我们实际编程的时候如何取获取文件的属性信息呢? 我们能不能模拟ls -al 命令,写出一个我们自己的ls -al 命令呢? 本文尝试做这个事情。其中用到了获取文件属性的API,我们的主要目的就是学习这些API。
    在这里插入图片描述

    1. stat等获取文件属性函数

    1.1 函数原型

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    int stat(const char *pathname, struct stat *statbuf);
    int fstat(int fd, struct stat *statbuf);
    int lstat(const char *pathname, struct stat *statbuf);
    

    1.2 函数功能

    三个函数可以获取文件属性信息。文件包括很多种,普通文件,目录等7类

    • stat函数返回一个与此命名文件有关的信息结构

    1.3 三个函数区别

    • fstat函数获得已在文件描述符filedes上打开的文件的有关信息。
    • lstat函数类似于stat,但是当命名的文件是一个符号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的信息
    • stat与之相反,返回的是链接文件引用的文件的信息

    注意:

    //创建一个链接文件指令
    ln -s 文件名 链接名
    

    rm 删除的时候删除的是硬链接数

    1.4 函数参数

    • pathname
      文件的路径名
    • statbuf
      获取到的文件的属性存储的位置,后面详细解释。
    • fd
      已经打开的文件的描述符

    1.5 statbuf参数的类型 stat 结构体

    stat 结构体 用于存储获取到的文件属性,结构体的定义如下:

    struct stat {
    	dev_t     st_dev;     /* ID of device containing file */
    	ino_t     st_ino;     /* inode number */
    	mode_t    st_mode;    /* protection */
    	nlink_t   st_nlink;   /* number of hard links */
    	uid_t     st_uid;     /* user ID of owner */
    	gid_t     st_gid;     /* group ID of owner */
    	dev_t     st_rdev;    /* device ID (if special file) */
    	off_t     st_size;    /* total size, in bytes */
    	blksize_t st_blksize; /* blocksize for file system I/O */
    	blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    	time_t    st_atime;   /* time of last access */
    	time_t    st_mtime;   /* time of last modification */
    	time_t    st_ctime;   /* time of last status change */
    };
    

    下面我们介绍其中的一些字段。

    1.5.1 结构体的st_ino字段

    用于标识 文件的节点号。

    1.5.2 结构体的 st_mode 字段

    该字段用于标识文件的 类型、文件的用户权限等。
    st_mode是个32位的整型变量,不过现在的linux操作系统只用了低16位(估计是鉴于以后拓展的考虑)。
    在这里插入图片描述

    1.5.1.1 先看File type属性区域

    它位于st_mode的bit12 ~ bit15。在现代linux操作系统上文件类型共分为7种,分别是:

    • 普通文件(regular file)
    • 目录(directory)
    • 字符设备(character device)
    • 块设备(block device)
    • 管道(FIFO)
    • 符号链接文件(symbolic link)
    • 套接口文件(socket)

    获取文件类型的方式:

    • 第一种方式:通过带参宏的方式。
      系统定义了多个带参数的宏用于判断st_mode,man 7 inode 可以查看。
    S_ISREG(m)  is it a regular file?
    S_ISDIR(m)  directory?
    S_ISCHR(m)  character device?
    S_ISBLK(m)  block device?
    S_ISFIFO(m) FIFO (named pipe)?
    S_ISLNK(m)  symbolic link?  (Not in POSIX.1-1996.)
    S_ISSOCK(m) socket?  (Not in POSIX.1-1996.)
    
    带参宏的实现
    #define S_ISLNK(m)      (((m) & S_IFMT) == S_IFLNK)  
    #define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)  
    #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)  
    #define S_ISCHR(m)      (((m) & S_IFMT) == S_IFCHR)  
    #define S_ISBLK(m)      (((m) & S_IFMT) == S_IFBLK)  
    #define S_ISFIFO(m)     (((m) & S_IFMT) == S_IFIFO)  
    #define S_ISSOCK(m)     (((m) & S_IFMT) == S_IFSOCK)  
    
    • 第二种方式:通过宏的形式。
    S_IFMT     0170000   bit mask for the file type bit field
    
    S_IFSOCK   0140000   socket
    S_IFLNK    0120000   symbolic link
    S_IFREG    0100000   regular file
    S_IFBLK    0060000   block device
    S_IFDIR    0040000   directory
    S_IFCHR    0020000   character device
    S_IFIFO    0010000   FIFO
    

    每一个值是一个8进制的数,st_mode 用了低16位。使用文件的st_mode 位与S_IFMT得到的结果就是下面的7种文件类型。

    1.5.1.2 st_mode的再看其它位

    在这里插入图片描述他们用于确定用户的权限。我们可以通过系统定义的宏来获取。

    // 用户 组 其它 的权限
    S_ISUID     04000   set-user-ID bit
    S_ISGID     02000   set-group-ID bit (see below)
    S_ISVTX     01000   sticky bit (see below)
    // user	权限
    S_IRWXU     00700   owner has read, write, and execute permission
    S_IRUSR     00400   owner has read permission      Is read user ?  是否有读权限。
    S_IWUSR     00200   owner has write permission
    S_IXUSR     00100   owner has execute permission
    // group 权限
    S_IRWXG     00070   group has read, write, and execute permission
    S_IRGRP     00040   group has read permission
    S_IWGRP     00020   group has write permission
    S_IXGRP     00010   group has execute permission
    
    S_IRWXO     00007   others (not in group) have read,  write,  and execute permission
    S_IROTH     00004   others have read permission
    S_IWOTH     00002   others have write permission
    S_IXOTH     00001   others have execute permission
    

    1.5.4 st_uid

    用于标识文件的拥有者id。当我们知道了用户id后,可以将用户id转化为用户名。因为用户id一一映射着一个用户名。获取用户名的API如下:

    #include <sys/types.h>
    #include <pwd.h>
    struct passwd *getpwuid(uid_t uid);
    

    函数参数:

    • uid : 用户ID

    函数返回值:

    • passwd 结构体指针
    struct passwd {
    	char   *pw_name;       /* username */
    	char   *pw_passwd;     /* user password */
    	uid_t   pw_uid;        /* user ID */
    	gid_t   pw_gid;        /* group ID */
    	char   *pw_gecos;      /* user information */
    	char   *pw_dir;        /* home directory */
    	char   *pw_shell;      /* shell program */
    };
    

    1.5.5 st_gid

    用于标识文件所属的用户组id。当我们知道了用户组id后,可以将用户id转化为用户组名。因为用户组名id一一映射着一个用户组名。获取用户组名的API如下:

    #include <sys/types.h>
    #include <grp.h>
    struct group *getgrgid(gid_t gid);
    

    函数参数:

    • gid :用户组ID

    函数返回值:

    • group 结构体指针
    struct group {
                   char   *gr_name;       /* group name */
                   char   *gr_passwd;     /* group password */
                   gid_t   gr_gid;        /* group ID */
                   char  **gr_mem;        /* group members */
    };
    

    1.5.6 st_atime

    用于存储文件的最后访问时间。

    1.5.7 st_mtime

    用于存储文件的最后修改时间。

    2. 目录操作

    2.1 打开目录

    #include <sys/types.h>
    #include <dirent.h>
    
    DIR *opendir(const char *name);
    DIR *fdopendir(int fd);
    
    • 函数参数
      要打开的目录的目录名
    • 函数返回值
      如果name是一个合法的目录名,opendir函数返回这个目录的句柄。返回的这个句柄主要给读目录函数readdir用的。
      如果是一个非法的目录名,此函数返回NULL。

    2.2 读一个目录

     #include <dirent.h>
      struct dirent *readdir(DIR *dirp);
    
    • 函数参数:
      需要打开的目录的指针。
    • 函数返回值:
      readdir函数需要opendir得到的句柄,每调用一次,返回当前目录中一个文件的信息。文件信息的由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; not supported
                                                  by all filesystem types */
    	char           d_name[256]; /* Null-terminated filename */
    };
    

    这个结构体我们需要关注的是最后一个字段。我们可以通过它来得到这个目录都包含有哪些文件。

    2.3 改变当前进程的工作目录

    #include <unistd.h>
    int chdir(const char *path);
    
    • 函数参数:
      更改后的目录

    • 函数返回值:

    3. 书写自己的 ls -al 命令

    有了上述的基础后,我们就可以来书写自己的ls -al 命令了。

  • 相关阅读:
    Nginx入门(三)——正向代理
    Nginx入门(二)——双机热备
    Socket
    TCP和UDP
    主线程等待子线程结束后再运行
    H5s播放rtsp和rtmp视频
    Thread.sleep()和Thread.currentThread().sleep()区别
    OpenLayer3入门——[一]
    事件绑定
    cmake和json安装
  • 原文地址:https://www.cnblogs.com/lasnitch/p/12764116.html
Copyright © 2020-2023  润新知