C++学习笔记day26-----UC

获取文件的元数据
在前面的学习中,对文件的操作,都是针对于文件的内容。
文件的属性和权限称为文件的元数据。这些内容和文件的内容是分开存放的。
系统提供了下述函数用于获取一个文件的元数据:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
功能:获取文件的元数据
参数:
pathname:指定文件的路径
buf:将文件的元数据填充到buf指定的空间里
返回值:
success:返回0
error:返回-1,设置errno
struct stat {
    dev_t     st_dev;         /* ID of device containing file 设备的ID*/
    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 拥有者用户的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;     /* blocksize 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
};

注意stat结构体,函数stat(2)第二个参数是一个结构体的地址。它接受stat(2)函数返回的内容。
stat结构体中的成员描述了一个文件的元数据。
可以看到,再stat结构体中,返回的是文件属主的UID和文件属组的GID,仅仅是一个数字,系统提供了下列函数,可以通过UID和GID来获取属主和数组的其他信息(在linux中,用户属性的记录文件是/etc/passwd,组属性的记录文件是/etc/group):

#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
功能:从passwd文件中获取一条记录
参数:
uid:指定要找的UID
返回值:
成功:返回有效地址
error:NULL ,没找到,或者错误,如果是错误,errno被设置
    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 */
    };

#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
功能:返回组文件中的一条记录
参数:
gid:指定的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 */
};
NULL 或者出错,出错的时候会设置errno的值

在结构体stat的成员变量中,访问时间返回的是一个长整型的变量,这种格式不利于阅读。系统提供了以下函数,可以将时间转换成易读的字符串格式:

#include <time.h>
char *ctime(const time_t *timep);

下面通过一个例子,来打印一个文件的属性:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <stdlib.h>
#include <grp.h>
#include <time.h>
int main(int argc,char *argv[]){
    struct stat buf = {0};
    int flag = stat(argv[1],&buf);
    if(flag == -1){
        perror("stat error");
        return -1;
    }
    //解析buf中的每一个成员
    printf("inode number:%lu\n",buf.st_ino);
    switch(buf.st_mode & S_IFMT){
        case S_IFSOCK : 
            printf("s");
            break;
        case S_IFREG : 
            printf("-");
            break;
        default : 
            break;
    }
    (buf.st_mode & S_IRUSR) ?printf("r"):printf("-");
    (buf.st_mode & S_IWUSR) ?printf("w"):printf("-");
    (buf.st_mode & S_IXUSR) ?printf("x"):printf("-");
    (buf.st_mode & S_IRGRP) ?printf("r"):printf("-");
    (buf.st_mode & S_IWGRP) ?printf("w"):printf("-");
    (buf.st_mode & S_IXGRP) ?printf("x"):printf("-");
    (buf.st_mode & S_IROTH) ?printf("r"):printf("-");
    (buf.st_mode & S_IWOTH) ?printf("w"):printf("-");
    (buf.st_mode & S_IXOTH) ?printf("x "):printf("- ");
    printf("%d ",buf.st_nlink);
    printf("%s ",getpwuid(buf.st_uid) -> pw_name);
    printf("%s ",getgrgid(buf.st_gid) -> gr_name);
    printf("%lu ",buf.st_size);
    printf("%s ",ctime(&buf.st_ctime));
    return 0;
}

文件夹的操作
文件夹的内容包括:文件和文件夹。
文件夹的操作权限和一般文件代表的意思不同。
r:能否读取这个文件夹下的文件/文件夹(但是!如果具有该文件夹下的文件/文件夹的操作权限,是可以操作的,只是说对当前的文件夹没有可以阅读其内容的权限)
w:能否增加和减少这个文件夹下的文件/文件夹的数量
x:决定能否通过这个文件夹
如果要直观的替换上述三个权限的情况,可以使用chmod来改变一个文件夹的权限,然后用指令去验证。

系统提供了以下函数,用于操作文件夹:

#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开一个文件夹
参数:
name:指定要打开的文件夹,位置定位在文件夹的首条记录上
返回值:
error:NULL。errno被设置
success:返回一个地址

DIR对于我们来说是透明的

#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭一个文件夹
参数:
dirp:opendir的返回值,要关闭的文件夹流
返回值:
success:返回0
error:返回 -1,errno被设置

#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:
参数:
dirp:opendir的返回值,指定了文件夹流中读取数据
返回值:
NULL,到达了文件夹的末尾,errno不会被设置;
或者错误,errno被设置

成功,返回如下结构体的地址
struct dirent
{
    __ino_t d_ino;
    __off_t d_off;
    unsigned short int d_reclen;
    unsigned char d_type;
    char d_name[256];
};

下面通过一个程序来演示上述函数的使用:

#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc,char *argv[]){
    //通过argv打开一个文件夹
    DIR *p_dir = opendir(argv[1]);
    if(p_dir == NULL){
        perror("opendir is error");
        return -1;
    }
    //打开文件夹成功
    printf("opendir is success!\n");
    struct dirent *p_rdir = NULL;
    while((p_rdir = readdir(p_dir)) != NULL){
        printf("name:%s......inode:%lu\n"\
            ,p_rdir -> d_name,p_rdir -> d_ino);
    }//每次读取文件夹中的内容的时候,都会导致位置指针移动,所以可以循环读取,直到文件夹中的最后一个成员

    //关闭文件夹
    closedir(p_dir);
    return 0;
}

在读取文件夹内容的时候,和读取文件的内容是类似的,文件夹的位置指针指向下一个要读取的文件/文件夹。每次读取之后,位置指针都会移动到相应的位置。
readdir(2)通过值-结果的形式,将描述文件/文件夹情况的结构体返回。

文件锁的使用
当两个进程同时读写一个文件的时候,会出现不可预知的情况。
为了保证进程读写文件和文件内容的有效性,操作系统提供了文件锁机制。
当一个进程对文件访问的时候,对该文件上锁,其他进程对该文件访问的时候要先获取文件锁的类型,看看能否对文件进行访问。
操作系统,提供了两种锁的机制,建议锁和强制锁。
下述内容,对建议锁进行详细的解读。
锁分为读锁(共享锁)、写锁(互斥锁)
当一个文件上有一把写锁的时候,其他的进程时无法访问这个文件。
系统提供了函数用于操作文件锁:

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
功能:对文件描述符的操作
参数:
fd:要操作的文件描述符
cmd:对文件描述符的操作命令
一大堆
建议锁命令:
F_SETLK
F_SETLKW
F_GETLK
...:可变参数,取决于cmd
建议锁需要的参数:
struct flock {
               ...
               short l_type;    /* Type of lock: F_RDLCK,
                                   F_WRLCK, F_UNLCK */
               short l_whence;  /* How to interpret l_start:
                                   SEEK_SET, SEEK_CUR, SEEK_END */
               off_t l_start;   /* Starting offset for lock */
               off_t l_len;     /* Number of bytes to lock */
               pid_t l_pid;     /* PID of process blocking our lock
                                   (set by F_GETLK and F_OFD_GETLK) */
               ...
           };
返回值:
success:返回 0 
error:-1,errno被设置

下面用一个例子来演示上述函数:

/*pa*/
#include<stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char *argv[]){
    struct flock lock;
    int fd = open(argv[1],O_RDWR);
    if(fd == -1){
        perror("open file error");
        return -1;
    }
    printf("open file success\n");

    lock.l_type = F_RDLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 6;

    int flag_fcntl = fcntl(fd,F_SETLK,&lock);
    if(flag_fcntl == -1){
        perror("test lock error\n");
        return -1;
    }
    printf("write lock success");
    getchar();
    close(fd);
    return 0;
}
------------------------------------------------
/*pb*/
#include<stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char *argv[]){
    struct flock lock;
    int fd = open(argv[1],O_RDWR);
    if(fd == -1){
        perror("open file error");
        return -1;
    }
    printf("open file success\n");

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 6;

    int flag_fcntl = fcntl(fd,F_SETLK,&lock);
    if(flag_fcntl == -1){
        perror("test lock error\n");
        return -1;
    }

    close(fd);
    return 0;
}
------------------------------------------------
/*pc*/
#include<stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char *argv[]){
    struct flock lock;
    int fd = open(argv[1],O_RDWR);
    if(fd == -1){
        perror("open file error");
        return -1;
    }
    printf("open file success\n");

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 6;

    int flag_fcntl = fcntl(fd,F_GETLK,&lock);
    if(flag_fcntl == -1){
        perror("test lock error\n");
        return -1;
    }

    if(lock.l_type == F_UNLCK){
        printf("can lock\n");
    }
    else{
        printf("flock's pid:%d\n",lock.l_pid);
    }
    close(fd);
    return 0;
}

pa函数,向文件加一把读锁;
pb函数,向文件加一把写锁;
pc函数,获取文件上的锁,询问是否可以加写锁;

猜你喜欢

转载自blog.csdn.net/displaymessage/article/details/80262278