第03章 Linux的文件属性与目录

文档配套视频讲解链接地址

  1. 腾讯课堂视频链接地址 : 物联网-嵌入式Linux应用开发课程

第03章 Linux的文件属性与目录

3.1 获取文件属性

1. stat 函数
  • 函数原型
int stat(const char *pathname, struct stat *statbuf);
struct stat {
    dev_t     st_dev;         /* ID of device containing file */  文件的设备号 , 这个和驱动有关系的参数
    ino_t     st_ino;         /* Inode number */   文件的唯一ID号, 类似身份证号  
    mode_t    st_mode;        /* File type and mode */ 文件的权限 可读可写可执行, 用户 组 其他 
    nlink_t   st_nlink;       /* Number of hard links */ 硬链接个数 
    uid_t     st_uid;         /* User ID of owner */  用户id号 
    gid_t     st_gid;         /* Group ID of owner */ 组id号
    dev_t     st_rdev;        /* Device ID (if special file) * / 特殊文件的设备号
    off_t     st_size;        /* Total size, in bytes */   文件大小
    blksize_t st_blksize;     /* Block size for filesystem I/O */ 在文件系统中, 一个块多少个字节
    blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */ 这个文件占用多少个块 

    /* Since Linux 2.6, the kernel supports nanosecond
                  precision for the following timestamp fields.
                  For the details before Linux 2.6, see NOTES. */

    struct timespec st_atim;  /* Time of last access */   最后访问时间 
    struct timespec st_mtim;  /* Time of last modification */  最后修改时间
    struct timespec st_ctim;  /* Time of last status change */ 最后状态改变时间 

    #define st_atime st_atim.tv_sec      /* Backward compatibility */ 最后访问的秒数, 用时需要转换成标准时间
    #define st_mtime st_mtim.tv_sec
    #define st_ctime st_ctim.tv_sec
};
  • 函数功能
    • 获取文件的属性信息
  • 函数参数
    • pathname: 文件名
    • statbuf : 保存文件属性信息的结构体指针
  • 函数返回值
    • 成功返回: 0
    • On success, zero is returned.
    • 失败返回 :
      • -1 并设置errno
      • On error, -1 is returned, and errno is set appropriately.
2. Inode示意图
  • 文件系统的分区表

  • 文件名类似人的姓名

  • Inode 号类似人的身份证号

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ADk4WN0d-1670758252682)(https://gitee.com/embmaker/cloudimage/raw/master/img/20221014135738.png)]

3. fstat 函数
  • 函数原型
int fstat(int fd, struct stat *statbuf);
  • 函数功能
    • 获取已经打开文件的属性信息
  • 函数参数
    • fd: 已经打开的文件
    • statbuf : 保存文件属性信息的结构体指针
  • 函数返回值
    • 成功返回: 0
    • On success, zero is returned.
    • 失败返回 :
      • -1 并设置errno
      • On error, -1 is returned, and errno is set appropriately.
4. getpwuid 函数
  • 函数原型
struct passwd *getpwuid(uid_t uid);

// 解释: 
The  getpwuid()  function  returns  a pointer to a structure containing the broken-out fields of the
    record in the password database that matches the user ID uid.

    The passwd structure is defined in <pwd.h> as follows:

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 */
};
  • 函数功能
    • 根据文件的uid来获取用户名
  • 函数参数
    • uid: 文件的所有者的id号
  • 函数返回值
    • 成功返回: 结构体的首地址
    • 失败返回 :
      • NULL 并设置errno
5. getgrgid 函数
  • 函数原型
struct group *getgrgid(gid_t gid);
struct group {
    char   *gr_name;        /* group name */  组的名称 
    char   *gr_passwd;      /* group password */
    gid_t   gr_gid;         /* group ID */
    char  **gr_mem;         /* NULL-terminated array of pointers
                                          to names of group members */
};
  • 函数功能
    • 根据文件的gid来获取组的用户名
  • 函数参数
    • gid: 文件的所有组的id号
  • 函数返回值
    • 成功返回: 结构体的首地址
    • 失败返回 :
      • NULL 并设置errno
4. 实例28 实现stat命令的功能
  • 使用stat函数来实现stat命令的功能

  • 源文件

05-linuxio/28-stat.c
  • 源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

int get_timezone(void)
{
    // 获取系统时间的秒数 1970 01 01 00:00:00 到此时的一个秒数 
    time_t t1 =  time(NULL); // 这个秒数, 会有时区的偏移 , 基于当前时区的一个秒数 
    // printf("t1=%ld\n",t1);  // t1 是东8区的秒数 

    // 秒数转时间结构体 
    struct tm *tp =  gmtime(&t1); // 这个函数 输出的时间是基准时间, 时区为0的基准时间
    time_t t2 =  mktime(tp); // 把时间结构体 struct tm  转成 time_t 的秒数 
    // printf("t2=%ld\n",t2);  // t2 是0时区的秒数 
    // printf("t1-t2=%ld\n",t1-t2);  // 本地时间 - 基准时间
    // printf("t1-t2=%ld\n",(t1-t2)/36);  // (本地时间 - 基准时间) 换算为小时
    return (t1-t2)/36;

}

int main(int argc, char const *argv[])
{
    struct stat st;
    if (argc != 2)
    {
        fprintf(stderr, "程序错误:运行程序时请带入参数(./28-stat filename)\n");
        exit(-1);
    }
    int ret = stat(argv[1], &st);
    if (ret < 0)
    {
        perror("stat");
        exit(-1);
    }
    printf("文件: %s\n", argv[1]);        // 输出文件名
    printf("大小: %ld\t\t", st.st_size);  // 输出文件大小  \t 加上一个tab按键 , 等于4个空格
    printf("块: %ld\t\t", st.st_blocks);  // 输出文件占用的块
    printf("IO块: %ld\t", st.st_blksize); // 文件系统的块大小
    switch (st.st_mode & S_IFMT)
    {
    case S_IFBLK:
        printf("普通文件\n");
        break;
    case S_IFCHR:
        printf("字符设备\n");
        break;
    case S_IFDIR:
        printf("目录\n");
        break;
    case S_IFIFO:
        printf("管道文件\n");
        break;
    case S_IFLNK:
        printf("符号连接\n");
        break;
    case S_IFREG:
        printf("普通文件\n");
        break;
    case S_IFSOCK:
        printf("套接字\n");
        break;
    default:
        printf("unknown?\n");
        break;
    }

    printf("设备: %lxh/%ldd\t", st.st_dev, st.st_dev); // 输出文件大小
    printf("Inode: %ld\t", st.st_ino);                 // 输出文件的Inode号
    printf("硬链接: %ld\n", st.st_nlink);              // 输出文件的硬链接

    // 保留st_mode的低9位 , 1个8进制的数占用3位
    printf("权限: (%#o/", st.st_mode & 0777); // 输出文件的8进制的权限

    /**********文件类型*********************************************************/
    switch (st.st_mode & S_IFMT)
    {
    case S_IFBLK:
        printf("b");
        break;
    case S_IFCHR:
        printf("c");
        break;
    case S_IFDIR:
        printf("d");
        break;
    case S_IFIFO:
        printf("p");
        break;
    case S_IFLNK:
        printf("l");
        break;
    case S_IFREG:
        printf("-");
        break;
    case S_IFSOCK:
        printf("s");
        break;
    default:
        printf("unknown?\n");
        break;
    }
    /*************用户权限************************************/
    // 获取用户的可读权限
    if (st.st_mode & S_IRUSR)
        printf("r");
    else
        printf("-");

    // 获取用户的可写权限
    if (st.st_mode & S_IWUSR)
        printf("w");
    else
        printf("-");

    // 获取用户的可执行权限
    if (st.st_mode & S_IXUSR)
        printf("x");
    else
        printf("-");

    /*****************组的权限*******************************/
    // 获取组的可读权限
    if (st.st_mode & S_IRGRP)
        printf("r");
    else
        printf("-");

    // 获取组的可写权限
    if (st.st_mode & S_IWGRP)
        printf("w");
    else
        printf("-");

    // 获取组的可执行权限
    if (st.st_mode & S_IXGRP)
        printf("x");
    else
        printf("-");
    /*****************其他用户的权限*******************************/
    // 获取其它的可读权限
    if (st.st_mode & S_IROTH)
        printf("r");
    else
        printf("-");

    // 获取其它的可写权限
    if (st.st_mode & S_IWOTH)
        printf("w");
    else
        printf("-");

    // 获取其它的可执行权限
    if (st.st_mode & S_IXOTH)
        printf("x");
    else
        printf("-");
    printf(")\t");
    /*****************文件所有者*******************************/
    struct passwd * pw =  getpwuid(st.st_uid) ; // 根据uid获取用户名
    printf("Uid: (%d/%s)\t", st.st_uid, pw->pw_name);
    struct group  *grp = getgrgid(st.st_gid)  ;  // 根据gid获取 组的名称
    printf("Gid: (%d/%s)\n", st.st_gid, grp->gr_name);

    struct tm *tmp = localtime(&st.st_atime); //   st_atime 就是秒数  最后访问时间
    printf("最近访问: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
           tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min,
           tmp->tm_sec, st.st_atim.tv_nsec, get_timezone());



    tmp = localtime(&st.st_mtime); //   st_atime 就是秒数 最后更改时间 
    printf("最近访问: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
           tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min,
           tmp->tm_sec, st.st_mtim.tv_nsec, get_timezone());


    tmp = localtime(&st.st_ctime); //   st_atime 就是秒数 最后状态改动时间
    printf("最近访问: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
           tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min,
           tmp->tm_sec, st.st_ctim.tv_nsec, get_timezone());
    return 0;
}

  • 运行结果
linux@ubuntu:~/work/emb2207/05-linuxio$ ./28-stat 01-fopen.c 
文件: 01-fopen.c
大小: 1110: 8           IO块: 4096      普通文件
设备: 801h/2049d        Inode: 3017194  硬链接: 1
权限: (0664/-rw-rw-r--) Uid: (1000/linux)       Gid: (1000/linux)
最近访问: 2022-10-14 08:00:08.026939918 +0800
最近访问: 2022-10-14 08:00:08.309500914 +0800
最近访问: 2022-10-14 08:00:08.309500914 +0800
linux@ubuntu:~/work/emb2207/05-linuxio$ stat 01-fopen.c 
  文件:01-fopen.c
  大小:1110            块:8          IO 块:4096   普通文件
设备:801h/2049d        Inode:3017194     硬链接:1
权限:(0664/-rw-rw-r--)  Uid:( 1000/   linux)   Gid:( 1000/   linux)
最近访问:2022-10-13 10:00:40.026939918 +0800
最近更改:2022-10-11 15:03:12.309500914 +0800
最近改动:2022-10-11 15:03:12.309500914 +0800
创建时间:-
linux@ubuntu:~/work/emb2207/05-linuxio$ 
  • 这个程序有bug, 问题是
linux@ubuntu:~/work/emb2207/05-linuxio$ ./28-stat 01-fopen.c 
文件: 01-fopen.c
大小: 1110: 8           IO块: 4096      普通文件
设备: 801h/2049d        Inode: 3017194  硬链接: 1
权限: (0664/-rw-rw-r--) Uid: (1000/linux)       Gid: (1000/linux)
最近访问: 2022-10-14 08:00:08.026939918 +0800
最近访问: 2022-10-14 08:00:08.309500914 +0800
最近访问: 2022-10-14 08:00:08.309500914 +0800
    
// 输出的时间都是一样的 , 这个问题解决请参考如下代码
  • 问题解决核心代码
    int timezone = get_timezone(); // 把时区单独提取出来进行保存 

    struct tm *tmp = localtime(&st.st_atime); //   st_atime 就是秒数  最后访问时间
    printf("最近访问: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
           tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min,
           tmp->tm_sec, st.st_atim.tv_nsec, timezone);

    tmp = localtime(&st.st_mtime); //   st_mtime 就是秒数 最后更改时间 
    printf("最近更改: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
           tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min,
           tmp->tm_sec, st.st_mtim.tv_nsec, timezone);


    tmp = localtime(&st.st_ctime); //   st_ctime 就是秒数 最后状态改动时间
    printf("最近改动: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
           tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min,
           tmp->tm_sec, st.st_ctim.tv_nsec, timezone);

3.2 目录操作

1. opendir 打开目录
  • 函数原型
DIR *opendir(const char *name);
/* This is the data type of directory stream objects.
   The actual structure is opaque to users.  */
typedef struct __dirstream DIR;
  • 函数功能
    • 打开指定的目录
  • 函数参数
    • name: 要打开目录的名称
  • 函数返回值
    • 成功返回: 结构体的首地址
    • 失败返回 :
      • NULL 并设置errno
      • On error, NULL is returned, and errno is set appropriately.
2. closedir 关闭目录
  • 函数原型
int closedir(DIR *dirp);
  • 函数功能
    • 关闭已经打开的目录
  • 函数参数
    • dirp: 要关闭的目录指针
  • 函数返回值
    • 成功返回: 0
    • 失败返回 :
      • -1 并设置errno
      • On error, -1 is returned, and errno is set appropriately.
3. readdir 读目录
  • 函数原型
struct dirent *readdir(DIR *dirp);
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 */   目录中的内容 , 目录内有子目录或文件名
};
  • 函数功能
    • 读已经打开的目录
  • 函数参数
    • dirp: 要读目录的指针
  • 函数返回值
    • 成功返回: 结构体的首地址
    • NULL 表示目录读完 , 不设置errno
    • If the end of the directory stream is reached, NULL is returned and errno is not changed
    • 失败返回 :
      • NULL 并设置errno
      • If an error occurs, NULL is returned and errno is set appropriately.
4. rmdir 删除目录
  • 函数原型
int rmdir(const char *pathname);
  • 函数功能
    • 删除指定的目录
  • 函数参数
    • pathname: 要删除的目录
  • 函数返回值
    • 成功返回: 0
    • On success, zero is returned.
    • 失败返回 :
      • -1并设置errno
      • On error, -1 is returned, and errno is set appropriately.
5. mkdir 创建目录
  • 函数原型
int mkdir(const char *pathname, mode_t mode);
  • 函数功能
    • 用给定的权限创建一个目录
  • 函数参数
    • pathname: 要创建的目录
    • mode : 创建目录的权限, 和open函数的权限一样
  • 函数返回值
    • 成功返回: 0
    • On success, zero is returned.
    • 失败返回 :
      • -1并设置errno
      • On error, -1 is returned, and errno is set appropriately.
6. chdir 切换目录
  • 函数原型
int chdir(const char *path);
  • 函数功能
    • 切换目录, 等同于命令的cd
  • 函数参数
    • path: 要切换的目录
  • 函数返回值
    • 成功返回: 0
    • On success, zero is returned.
    • 失败返回 :
      • -1并设置errno
      • On error, -1 is returned, and errno is set appropriately.
7. 实例29 读取指定目录的内容
  • 使用opendir, readdir , closedir 读取目录中的内容

  • 源文件

05-linuxio/29-opendir.c
  • 源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char const *argv[])
{

    struct dirent *dt; 
    if(argc != 2)
    {
        fprintf(stderr,"错误:运行程序时请带入参数(./29-opendir path)\n"); 
        exit(-1); 
    }
    DIR * dirp =  opendir(argv[1]); 
    if(dirp == NULL)
    {
        perror("opendir");
        exit(-1); 
    }
    while( (dt=readdir(dirp)) != NULL )
    {
        if(strncmp(dt->d_name,".",1) == 0 ) continue; 
        printf("%s  ",dt->d_name); 

    }
    printf("\n"); 
    closedir(dirp); 
    return 0;
}

  • 运行结果
linux@ubuntu:~/work/emb2207/05-linuxio$ ./29-opendir /home/linux/
Downloads  Templates  Videos  Desktop  Pictures  snap  Documents  work  Public  Music  id_rsa.pub  
linux@ubuntu:~/work/emb2207/05-linuxio$ ls /home/linux/
Desktop  Documents  Downloads  id_rsa.pub  Music  Pictures  Public  snap  Templates  Videos  work
linux@ubuntu:~/work/emb2207/05-linuxio$ 
8. 实例 30 综合练习myls
  • 编程实现ls 和 ls -l 命令的功能

  • 提示 : 封装2个函数 , process_ls 和 process_ls_l

  • 源文件

05-linuxio/30-myls.c
  • 源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

int process_ls(const char *arg)
{
    // printf("argv=%s\n",arg);
    // printf("process_ls\n");
    struct dirent *dt;
    DIR *dirp = opendir(arg);
    if (dirp == NULL)
    {
        perror("opendir");
        exit(-1);
    }
    while ((dt = readdir(dirp)) != NULL)
    {
        if (strncmp(dt->d_name, ".", 1) == 0)
            continue;
        printf("%s  ", dt->d_name);
    }
    printf("\n");
    closedir(dirp);
    return 0;
}

int process_ls_l(const char *arg)
{
    // printf("argv=%s\n", arg);
    // printf("process_ls_l\n");
    struct dirent *dt;
    struct stat st;
    char filename[300] = {0};
    struct tm *tmp;
    DIR *dirp = opendir(arg);
    if (dirp == NULL)
    {
        perror("opendir");
        exit(-1);
    }
    while ((dt = readdir(dirp)) != NULL)
    {
        if (strncmp(dt->d_name, ".", 1) == 0)
            continue;

        if (arg[strlen(arg) - 1] == '/')
        {
            sprintf(filename, "%s%s", arg, dt->d_name);
        }
        else
        {
            sprintf(filename, "%s/%s", arg, dt->d_name);
        }

        //printf("%s\n", filename);

        int ret = stat(filename, &st);
        if (ret < 0)
        {
            perror("stat");
            exit(-1);
        }
        /**********文件类型*********************************************************/
        switch (st.st_mode & S_IFMT)
        {
        case S_IFBLK:
            printf("b");
            break;
        case S_IFCHR:
            printf("c");
            break;
        case S_IFDIR:
            printf("d");
            break;
        case S_IFIFO:
            printf("p");
            break;
        case S_IFLNK:
            printf("l");
            break;
        case S_IFREG:
            printf("-");
            break;
        case S_IFSOCK:
            printf("s");
            break;
        default:
            printf("unknown?\n");
            break;
        }
        /*************用户权限************************************/
        // 获取用户的可读权限
        if (st.st_mode & S_IRUSR)
            printf("r");
        else
            printf("-");

        // 获取用户的可写权限
        if (st.st_mode & S_IWUSR)
            printf("w");
        else
            printf("-");

        // 获取用户的可执行权限
        if (st.st_mode & S_IXUSR)
            printf("x");
        else
            printf("-");

        /*****************组的权限*******************************/
        // 获取组的可读权限
        if (st.st_mode & S_IRGRP)
            printf("r");
        else
            printf("-");

        // 获取组的可写权限
        if (st.st_mode & S_IWGRP)
            printf("w");
        else
            printf("-");

        // 获取组的可执行权限
        if (st.st_mode & S_IXGRP)
            printf("x");
        else
            printf("-");
        /*****************其他用户的权限*******************************/
        // 获取其它的可读权限
        if (st.st_mode & S_IROTH)
            printf("r");
        else
            printf("-");

        // 获取其它的可写权限
        if (st.st_mode & S_IWOTH)
            printf("w");
        else
            printf("-");

        // 获取其它的可执行权限
        if (st.st_mode & S_IXOTH)
            printf("x");
        else
            printf("-");

        /*****************硬链接的数量*****************************/
        printf(" %ld", st.st_nlink);
        /*****************文件所有者*******************************/
        struct passwd *pw = getpwuid(st.st_uid); // 根据uid获取用户名
        printf(" %s", pw->pw_name);
        struct group *grp = getgrgid(st.st_gid); // 根据gid获取 组的名称
        printf(" %s ", grp->gr_name);
        /*******************文件的大小*****************************/
        printf("%4ld ", st.st_size);
        /*******************文件的修改时间**************************/

        tmp = localtime(&st.st_mtime); //   st_mtime 就是秒数 最后更改时间
        printf("%02d月%02d %02d:%02d ", tmp->tm_mon + 1, tmp->tm_mday,
               tmp->tm_hour, tmp->tm_min );

        printf("%s\n",dt->d_name);
    }
    closedir(dirp);
    return 0;
}

int main(int argc, char const *argv[])
{

    struct dirent *dt;
    if (argc == 2) // ls /
    {
        process_ls(argv[1]); // path
    }
    else if (argc == 3) // ls -l /
    {
        process_ls_l(argv[2]); // path
    }
    else
    {
        fprintf(stderr, "错误:运行程序时请带入参数(./30-myls path 或者 ./myls -l path )\n");
        exit(-1);
    }
    return 0;
}

  • 运行结果
linux@ubuntu:~/work/emb2207/05-linuxio$ ls /home/linux/
Desktop  Documents  Downloads  id_rsa.pub  Music  Pictures  Public  snap  Templates  Videos  work
linux@ubuntu:~/work/emb2207/05-linuxio$ ls -l /home/linux/
总用量 44
drwxr-xr-x 2 linux linux 4096 96 08:48 Desktop
drwxr-xr-x 2 linux linux 4096 823 16:17 Documents
drwxr-xr-x 2 linux linux 4096 816 11:03 Downloads
-rw------- 1 linux linux  569 96 08:57 id_rsa.pub
drwxr-xr-x 2 linux linux 4096 816 11:03 Music
drwxr-xr-x 2 linux linux 4096 816 11:03 Pictures
drwxr-xr-x 2 linux linux 4096 816 11:03 Public
drwx------ 4 linux linux 4096 817 10:19 snap
drwxr-xr-x 2 linux linux 4096 816 11:03 Templates
drwxr-xr-x 2 linux linux 4096 816 11:03 Videos
drwxrwxr-x 3 linux linux 4096 920 09:23 work
linux@ubuntu:~/work/emb2207/05-linuxio$ 

    
// 功能如下: 
linux@ubuntu:~/work/emb2207/05-linuxio$ ./30-myls -l /home/linux
drwxr-xr-x 2 linux linux 4096 0816 11:03 Downloads
drwxr-xr-x 2 linux linux 4096 0816 11:03 Templates
drwxr-xr-x 2 linux linux 4096 0816 11:03 Videos
drwxr-xr-x 2 linux linux 4096 0906 08:48 Desktop
drwxr-xr-x 2 linux linux 4096 0816 11:03 Pictures
drwx------ 4 linux linux 4096 0817 10:19 snap
drwxr-xr-x 2 linux linux 4096 0823 16:17 Documents
drwxrwxr-x 3 linux linux 4096 0920 09:23 work
drwxr-xr-x 2 linux linux 4096 0816 11:03 Public
drwxr-xr-x 2 linux linux 4096 0816 11:03 Music
-rw------- 1 linux linux  569 0906 08:57 id_rsa.pub
linux@ubuntu:~/work/emb2207/05-linuxio$ ./30-myls -l /home/linux/
drwxr-xr-x 2 linux linux 4096 0816 11:03 Downloads
drwxr-xr-x 2 linux linux 4096 0816 11:03 Templates
drwxr-xr-x 2 linux linux 4096 0816 11:03 Videos
drwxr-xr-x 2 linux linux 4096 0906 08:48 Desktop
drwxr-xr-x 2 linux linux 4096 0816 11:03 Pictures
drwx------ 4 linux linux 4096 0817 10:19 snap
drwxr-xr-x 2 linux linux 4096 0823 16:17 Documents
drwxrwxr-x 3 linux linux 4096 0920 09:23 work
drwxr-xr-x 2 linux linux 4096 0816 11:03 Public
drwxr-xr-x 2 linux linux 4096 0816 11:03 Music
-rw------- 1 linux linux  569 0906 08:57 id_rsa.pub
linux@ubuntu:~/work/emb2207/05-linuxio$ ./30-myls  /home/linux/
Downloads  Templates  Videos  Desktop  Pictures  snap  Documents  work  Public  Music  id_rsa.pub  
linux@ubuntu:~/work/emb2207/05-linuxio$ ./30-myls  /home/linux
Downloads  Templates  Videos  Desktop  Pictures  snap  Documents  work  Public  Music  id_rsa.pub  
linux@ubuntu:~/work/emb2207/05-linuxio$ 

3.3 知识点补充

1. umask 函数
  • 函数原型
mode_t umask(mode_t mask);
  • 函数功能

    • 权限屏蔽
  • 函数参数

    • mask: 给的屏蔽位
    • 例如 : 0111 的屏蔽位, 将来的文件权限
    umask(0111)
    open("1.txt",O_RDWR|O_CREAT|O_APPEND,0664) ;  //设置新创建文件的权限位0664 
    // 最终的文件权限为: 
    // 0111 按位取反 与上 0664 , 才是文件最终的权限 
    //  =  ~0111 & 0664 
    //  =   0666 & 0664
    //  =   0664 
    
  • 函数返回值

    • 成功返回: 之前屏蔽位的值
    • This system call always succeeds and the previous value of the mask is returned.
2. 实例31 文件权限屏蔽位
  • 源文件
05-linuxio/31-umask.c
  • 源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
    mode_t mask = umask(0777);
    printf("mask = %#o\n", mask);

    // 最终的文件权限位:
    // = ~0777 & 0777
    // = 0000 & 0777
    // = 0000
    int fd = open("1.txt", O_RDWR | O_CREAT | O_APPEND, 0777); //设置新创建文件的权限位0777
    if (fd < 0)
    {
        perror("1:open");
        exit(-1);
    }
    printf("fd=%d\n", fd);

    umask(0);
    // 最终的文件权限位:
    // = ~0000 & 0777
    // = 0777 & 0777
    // = 0777
    int fd2 = open("2.txt", O_RDWR | O_CREAT | O_APPEND, 0777); //设置新创建文件的权限位0777
    if (fd2 < 0)
    {
        perror("2:open");
        exit(-1);
    }
    printf("fd2=%d\n", fd2);

    umask(02); // 系统默认的权限
    // 最终的文件权限位:
    // = ~0000 & 0777
    // = 0777 & 0777
    // = 0777
    int fd3 = open("3.txt", O_RDWR | O_CREAT | O_APPEND, 0777); //设置新创建文件的权限位0777
    if (fd3 < 0)
    {
        perror("2:open");
        exit(-1);
    }
    printf("fd3=%d\n", fd3);
    return 0;
} 
  • 运行结果
linux@ubuntu:~/work/emb2207/05-linuxio$ ./31-umask 
mask = 02
fd=3
fd2=4
fd3=5
linux@ubuntu:~/work/emb2207/05-linuxio$ ls -l 1.txt 2.txt 3.txt 
---------- 1 linux linux 0 1015 16:17 1.txt  // 0000
-rwxrwxrwx 1 linux linux 0 1015 16:17 2.txt  // 0777
-rwxrwxr-x 1 linux linux 0 1015 16:17 3.txt  // 0775 
3. access 函数
  • 函数原型
int access(const char *pathname, int mode);
  • 函数功能
    • 检查一个文件的权限(可读, 可写,可执行, 是否存在)
  • 函数参数
    • pathname: 要检查的文件名
    • mode :
      • F_OK : 测试文件是否存在
      • R_OK : 可读
      • W_OK : 可写
      • X_OK. : 可执行
  • 返回值:
    • 成功返回: 0
    • 失败返回: -1 并设置errno
    • On success (all requested permissions granted, or mode is F_OK and the file exists), zero is returned. On
      error (at least one bit in mode asked for a permission that is denied, or mode is F_OK and the file does not
      exist, or some other error occurred), -1 is returned, and errno is set appropriately.
4. 实例32 access
  • 检查一个文件是否存在, 如果存在就删除, 不存在创建

  • 源文件

05-linuxio/32-access.c
  • 源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{

    if (argc != 2)
    {
        fprintf(stderr, "错误:运行程序时请带入参数(./32-access filename)\n");
        exit(-1);
    }
    // 返回值为0 , 表示文件存在 
    // 返回值为-1 ,表示文件不存在
    if (access(argv[1],F_OK) == 0 )  // 文件存在
    {
        printf("%s:文件存在\n",argv[1]);
        remove(argv[1]); // 删除文件 
    }

    int fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, 0664); //设置新创建文件的权限位0777
    if (fd < 0)
    {
        perror("1:open");
        exit(-1);
    }
    printf("fd=%d\n", fd);

    return 0;
}

  • 运行结果
linux@ubuntu:~/work/emb2207/05-linuxio$ echo "goodbye" >>1.txt
linux@ubuntu:~/work/emb2207/05-linuxio$ ls -l 1.txt 
-rw-rw-r-- 1 linux linux 8 1015 16:55 1.txt
linux@ubuntu:~/work/emb2207/05-linuxio$ ./32-access 1.txt 
1.txt:文件存在
fd=3
linux@ubuntu:~/work/emb2207/05-linuxio$ cat 1.txt 
linux@ubuntu:~/work/emb2207/05-linuxio$ 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值