Unix_Linux操作系统-笔记Day4(文件操作,文件同步)

Day4

lseek

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
  • 设置文件位置指针
  • 返回值 文件指针的位置 功能类似于ftell

练习1:实现一个Linux系统下计算文件大小的函数使用系统调用
homework
练习2:实现一个带覆盖检查的cp命令
homework


dup/dup2

#include <unistd.h>

int dup(int oldfd);
  • 复制文件描述符,操作系统会从未使用的文件描述符中选择一个小的返回
  • oldfd 被复制的文件描述符
int dup2(int oldfd, int newfd);
  • 复制指定的文件描述符,如果newfd已经被使用,则先关闭再复制
  • oldfd
  • newfd
  • 返回
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
void init(void){
    int fd = open("log.txt",O_RDWR|O_CREAT|O_APPEND,0644);
    dup2(fd,1);//如果是0,可以使用gets从日志中读取一行
}

int main(){
    init();//init后printf()打印的内容会直接写入log.txt
    int fd = dup(2);//fd = 1/2时(STDOUT/STDERR)向fd写入的数据会直接打印
    write(fd,"hello",5);
}

标准IO与系统IO比较

练习3 分别使用标准IO与系统IO随机写入100,0000个整数到文件,比较哪一种方法更快,为什么?homework

标准IO使用了缓冲区技术,而每次调用系统IO都要切换用户态和内核态


文件同步


sync/fsync/fdatasync

硬盘上一般会有一些缓冲区以此来提高数据写入效率,操作系统写入数据其实只是写入缓冲区,直到缓冲区满,才排队写入硬盘中

这种操作降低了写入的次数,但是提高了数据写入的延时,导致缓冲区中的数据与磁盘中的内容不同步

注意 此处所讲的缓冲区都指硬盘缓存

void sync(void);
  • 把所有缓冲区中的数据全部同步到磁盘
  • 注意 只是将数据同步到磁盘的命令,并不等等执行完后才返回,而是命令发布后立即返回
int fsync(int fd);
  • 指定df文件的缓冲区数据同步到磁盘,只针对一个文件,数据同步到磁盘后才返回
int fdatasync(int fd);
  • 指定df文件的缓冲区数据同步到磁盘,但仅是文件的数据并不同步文件的属性

fcntl

int fcntl(int fd,int cmd,.../* arg */);
  • cmd 操作指令,不同的操作指令决定后续参数的个数和类型
  • 注意 这是个变长参数的函数
int fcntl(int fd,int cmd, long newfd);
  • cmd F_DUPFD
  • 复制文件描述符,与fd操作同一个文件
  • 返回值 如果newfd没有使用则返回newfd;如果nrefd已经被占用,则返回一个不小于newfd的文件描述符

练习1:利用fcntl实现dup,dup2的功能
homework

int fcntl(int fd, int cmd, void/long);
  • 设置或获取文件描述符标志

  • cmd

    • F_GETFD
    • F_SETFD

    目前只能设置FD_CLOEXEC标志位

  • 返回值 0 新进程保持打开状态,1 新进程中关闭该文件描述符

int fcntl(int fd, int cmd, void/long);
  • 获取文件状态标志(当前文件打开的权限以及打开的方式)
  • cmd:
    • F_GETFL void
      • O_CREAT,O_EXCL,O_NOCTTY,O_TRUNC 不能获取到
    • 返回值 带有文件状态标志的int类型状态,需要与各标志相与得到
    • F_SETFL long
      • 仅能设置的有O_APPEND,O_ASYNC,O_DIRECT,O_NOATIME,O_NONBLOCK
    • 返回值 成功0 失败-1
#include <...>
void file_flags(int fd){
    struct Flags{
        int flag;
        char* name;
    }flags[] = {
        {O_RDONLY,"O_RDONLY"},
        {O_WRONLY,"O_WRONLY"},
        {O_RDWR,"O_RDWR"},
        {O_APPEND,"O_APPEND"},
        {O_ASYNC,"O_ASYNC"},
        {O_CLOEXEC,"O_CLOEXEC"},
        {O_SYNC,"O_SYNC"}
    };
    int flags = fcntl(fd,F_GETFL);
    for(int i=0;i<sizeof(flags)/sizeof(flags[0]);i++){
        if(flags[i].flag&flag)
            printf("%s\n",flags[i].name);
    }
}
int main(){
    int fd = open("A.TXT",O_WRONLY|O_RDONLY|O_SYNC|O_CLOEXEC);
    fcntl(fd,F_SETFL,O_ASYNC);
    file_flags(fd);
    close(fd);
}
int fcntl(int fd, int cmd, struct* flock);
  • 为文件加锁,能所整个文件,或其中的一部分内容
  • cmd
    • F_GETLK 获取锁的信息
    • F_SETLK 设置锁
    • F_SETLKW 测试锁
  • 读锁和读锁不冲突,读锁与写锁冲突,写锁与写锁冲突
  • 加锁并不能让其他进程打不开文件或不能操作,而是使用者都要遵守锁的约定,确保文件不混了(劝诫锁)
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) */
               ...
           };
#include <...>

int rlock(int fd){
    struct flock lock = {F_RDLOCK,SEEK_SET,0,0,-1};
    return fcntl(fd,f_SETLK,&lock);
}

int wlock(int fd){
    struct flock lock = {F_WRLOCK,SEEK_SET,0,0,-1};
    return fcntl(fd,f_SETLK,&lock);
}

void show_lock(int fd){
    struct flock lock = {};
    printf("获取锁%s\n",fcntl(fd,F_GETLK,&lock)?"失败":"成功");
    if(lock.l_type == F_UNLCK){
        printf("无锁\n");
    }else{
        printf("加锁进程:%d\n",lock.l_pid);
        printf("锁类型:%s\n",lock.l_type == F_RDLOCK?"读锁":"写锁");
        printf("从文件");
        switch(lock.l_whence){
            case SEEK_SET:printf("从文件开头");break;
            case SEEK_CUR:printf("从当前位置");break;
            case SEEK_END:printf("从文件末尾");break;
        }
        if(lock.l_start > 0){
            printf("右移%lu个字节开始",lock.l_start);
        }else if(lock.l_start < 0){
            printf("左移%lu个字节开始",lock.l_start);
        }

        if(lock.len){
            printf("加锁%lu个字节\n",lock.l_len);
        }
        else{
            printf("加锁到文件末尾\n");
        }
    }
}

int main(){
    int fd = open("a.txt",O_RDWR);
    printf("%d\n",rlock(fd));
    printf("%d\n",getpid());
    getchar();

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值