Ubuntu下UnixC的第六天

本文深入探讨了文件操作的底层细节,包括文件描述符的使用、文件锁的实现、文件元数据的获取以及文件夹操作的方法。通过具体示例介绍了如lseek、mmap、dup、opendir、readdir等系统调用的功能与应用,同时解析了库函数与系统调用之间的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回忆
一、lseek(2) 重新定位读写文件的位置
二、使用mmap将文件映射到进程的虚拟地址空间
在内存中对数据的更改直接反应到文件中
三、文件描述符的复制
dup (2)
dup2(2)
文件描述符的具体概念
文件输出重定向
文件输入重定向
四、获取文件的元数据
inode  i节点 每个文件都有自己的inode  且是唯一的
硬链接  软链接 原理
stat(2) struct stat结构体
uid gid 时间的处理 ctime
根据uid 和gid找到用户名字和用户组名字
结构体 成员  值-结果参数

权限的问题
文件类型

今天的内容:
一 获取文件的元数据(文件类型和权限)
-rw-rw-r-- 1 nan nan 615 1月  10 10:25 笔记
第一个字符代表文件的类型
-   普通文件
d   文件夹
c   字符设备文件
b   块设备文件
l   软连接文件
s   socket文件
p   管道文件
    
rw-rw-r-- 
属主owner   属组   other
 40775
170000
111
4
二 文件夹的操作
    427171 drwxrwxr-x 2 nan nan  4096 1月  10 11:34 hello
    rwx
    x 可通过
    r w 文件夹的内容是什么
    文件夹的内容就是文件夹里的文件或者文件夹
    如何才算对文件夹的内容进行写操作
    删除文件   新建文件

    使用函数对文件夹里的内容进行读操作(遍历)
    opendir(3)
     #include <sys/types.h>
       #include <dirent.h>

       DIR *opendir(const char *name);
    功能:打开一个文件夹
    参数:
    name:指定了文件夹的名字
    返回值:返回一个指向文件夹流的指针,指向文件夹下的第一个条目
        错误时返回NULL errno被设置
    closedir(3)
     #include <sys/types.h>

       #include <dirent.h>

       int closedir(DIR *dirp);
    功能:关闭文件夹
    参数: 
    dirp 指定要关闭的文件夹流
    返回值:成功返回0
        错误 -1  errno被设置


    readdir(3)
     #include <dirent.h>

       struct dirent *readdir(DIR *dirp);
    功能:从文件夹读取一个文件夹条目
    参数 
    dirp 指定了文件夹流
    返回值:成功返回指向结构体的指针
        返回NULL   到达了文件夹的末尾或者错误    
        如果是错误  errno被设置   
    
 struct dirent {
               ino_t          d_ino;       /* inode number */
               off_t          d_off;       /* not an offset; see NOTES */
               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]; /* filename */
           };
    


      cJSON
      docker容器
    

三 文件锁的使用
    两种  读锁(共享锁)  写锁(互斥锁)
    锁的实现又分为两种   建议锁  强制锁
如何使用文件锁
 #include <unistd.h>
       #include <fcntl.h>

       int fcntl(int fd, int cmd, ... /* arg */ );
功能:
参数:
    fd 指定了要操作的文件操作符
    cmd 
    F_SETLK  设置一把锁 加锁,如果有互斥锁,立即返回-1, errno被设置
    F_SETLKW   设置一把锁,加锁  如果有互斥锁 等待这把锁被释放
    F_GETLK    测试是否可以放置锁 如果返回的lock的l_type里是F_UNLOCK,说明可以放置锁。如果有其他进程已经放置互斥锁,返回持有该互斥锁的进程的pid到lock的l_pid字段里
    ... 可变参数  参数的个数 类型 取决于cmd
    
返回值:成功 0
    错误 -1 errno被设置

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) */
               ...
           };
编写代码如下   pa.c 完成对指定文件加读锁
          pb.c完成对指定文件加写锁
          pc.c测试文件是否可以加读锁
四 库函数和系统调用的关系
    fopen(3) fclose(3) fputc(3)  fgetc(3)
    open  read write  close
    演示代码 file.c
    fopen(3)首先为FILE类型的变量分配空间,然后分配一块用于文件操作的缓冲区。将缓冲区中的相应地址记录到FILE类型的变量空间的字段里。调用open,返回文件描述符,记录在fileno中。
    fgetc(3) 从参数中找到读取数据的缓冲区,从中读取数据,如果空间里有数据,立即返回,如果没有数据,调用read(2)从文件中读取数据到缓冲区,然后,fgetc获取到数据,立即返回。
    fputc(3)从参数中找到存放数据的缓冲区,如果有足够的空间,将数据放入缓冲区,立即返回,如果缓冲区空间不足,调用write(2)将缓冲的数据写入到文件,清空缓冲区,fputc将数据放入到缓冲然后返回
    fclose(3)首先将缓冲区中的数据同步到文件中,释放缓冲区,调用close(2)关闭文件描述符fileno。释放FILE类型变量的空间。
    库函数封装了系统调用
    缓冲文件,非缓冲文件
    库函数的效率比较高,可以跨操作系统。
五 文件操作的杂项
    access(2)
    getcwd(3)
    chdir(2)
    mkdir(2)
    rmdir(2)
    basename(3)
    dirname(3)
    link(2)硬链接
    unlink(2)
    chmod(2)
    rename(2)
    remove(3)
    symlink(2)
 

 

t_ls.c

#include<t_stdio.h>
#include<t_file.h>
#include<dirent.h>
int main(int argc,char* argv[]){
    //打开文件夹
    DIR *dir=opendir(".");
    if(!dir) E_MSG("open",-1);


    while(1){
    struct dirent *p=readdir(dir);

    if(!p)break;
    if(p->d_name=="."||p->d_name=="..")
        continue;
    printf("%s   ",p->d_name);
    }
    printf("\n");
    closedir(dir);
    return 0;
}
 

 

stat.c

#include<t_stdio.h>
#include<t_file.h>
#include<time.h>
#include<pwd.h>
#include<grp.h>
int main(int argc,char *argv[]){
    //获取文件的元数据,存储到buf
    struct stat buf;

    int s=stat(argv[1],&buf);
    if(s==-1) E_MSG("stat",-1);
    
    
    printf("hard links:%u\n",buf.st_nlink);
    printf("size:%ld\n",buf.st_size);
    printf("inode:%ld\n",buf.st_ino);
    printf("mtime:%s",ctime(&buf.st_mtime));
    printf("uid:%u\n",buf.st_uid);
    printf("username:%s\n",(getpwuid(buf.st_uid))->pw_name);
    printf("gid:%u\n",buf.st_gid);
    printf("group grname:%s\n",(getgrgid(buf.st_gid))->gr_name);
    printf("mode:%o\n",buf.st_mode);
    switch(buf.st_mode&S_IFMT){
        case S_IFDIR:
                printf("d");
                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("\n");
    return 0;
}
 

pa.c

#include<t_stdio.h>
#include<t_file.h>
#include<fcntl.h>

int main(int argc,char* argv[]){
    //给指定文件加读锁 argv【1】传递
    int fd=open(argv[1],O_RDONLY|O_CREAT);
    if(fd==-1) E_MSG("OPEN",-1);
    
    struct flock lock;    
    //初始化lock
    lock.l_type=F_RDLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=0;
    lock.l_len=6;
    int f=fcntl(fd,F_SETLK,&lock);
    if(f==-1) E_MSG("fcntl",-1);
    printf("read lock...\n");
//加写锁
    
    lock.l_type=F_WRLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=0;
    lock.l_len=6;
     fd=open(argv[1],O_WRONLY|O_CREAT);
    f=fcntl(fd,F_SETLK,&lock);
    if(f==-1) E_MSG("fcntl",-1);
    printf("write lock...\n");
    

    
    getchar();//保证当前进程不关闭,锁不消失
        //关闭文件描述符时,所有记录锁就没了
    
    

    close(fd);
    return 0;
}
 

pb.c

#include<t_stdio.h>
#include<t_file.h>
#include<fcntl.h>

int main(int argc,char* argv[]){
    //给指定文件加读锁 argv【1】传递
    int fd=open(argv[1],O_WRONLY|O_CREAT);
    if(fd==-1) E_MSG("OPEN",-1);
    
    struct flock lock;    
    //初始化lock
    lock.l_type=F_WRLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=0;
    lock.l_len=6;
    int f=fcntl(fd,F_SETLK,&lock);
    if(f==-1) E_MSG("fcntl",-1);
    printf("WRITE lock...\n");
    getchar();//保证当前进程不关闭,锁不消失
        //关闭文件描述符时,所有记录锁就没了
    if(f==-1) E_MSG("fcntl",-1);
    

    close(fd);
    return 0;
}
 

pc.c

#include<t_stdio.h>
#include<t_file.h>
#include<fcntl.h>

int main(int argc,char* argv[]){
    //给指定文件加读锁 argv【1】传递
    int fd=open(argv[1],O_RDONLY|O_CREAT);
    if(fd==-1) E_MSG("OPEN",-1);
    
    struct flock lock;    
    //初始化lock
    lock.l_type=F_RDLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=0;
    lock.l_len=6;
    int f=fcntl(fd,F_GETLK,&lock);
    if(f==-1) E_MSG("fcntl",-1);
    if(lock.l_type==F_UNLCK)
    printf("may read lock\n");
    else 
        printf("block proccess pid is%d\n",lock.l_pid);

        //关闭文件描述符时,所有记录锁就没了
    if(f==-1) E_MSG("fcntl",-1);
    

    close(fd);
    return 0;
}
 

file.c

#include<t_stdio.h>
int main(int argc,char*argv[]){
    FILE *fp=fopen(argv[1],"r");
    if(fp==NULL) E_MSG("open",-1);
    fclose(fp);
    return 0;
}
 

dir.c

#include<t_stdio.h>
#include<t_file.h>
#include<dirent.h>
int main(int argc,char* argv[]){
    //打开文件夹
    DIR *dir=opendir(argv[1]);
    if(!dir) E_MSG("open",-1);
    printf("open dir success...\n");
//关闭文件夹
    while(1){
    struct dirent *p=readdir(dir);

    if(!p)break;
    printf("file:%s\t inode:%lu\n",p->d_name,p->d_ino);
    }
    closedir(dir);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值