系统IO编程

常用函数

  • open(文件名,文件模式[, 文件权限]), 返回值是文件描述符

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int open(const char *pathname, int flags); // 多个flag用|连接,eg: flag1|falg2|...
    int open(const char *pathname, int flags, mode_t mode);
    
    flag描述
    O_RDONLY只读
    O_WRONLY只写
    O_RDWR可读可写
    O_CREAT如果文件不存在就建立
    O_EXCL与CREAT合用,用户建立文件(原子操作)
    O_APPEND追加模式,将指针移动到文件末尾
    O_DSYNC效果是每次write后将内核缓冲区的数据立即写入磁盘
    O_SYNC效果是每次write后将内核缓冲区的数据和元数据写入磁盘
    mode说明
    S_IRUSR允许文件所属者读文件
    S_IWUSR允许文件所属者写文件
    S_IXUSR允许文件所属者执行文件
    S_IRWXU允许文件所属者读、写、执行文件
    S_IRGRP允许同组用户读文件
    S_IWGRP允许同组用户写文件
    S_IXGRP允许同组用户执行文件
    S_IRWXG允许同组用户读、写、执行文件
    S_IROTH允许其他用户读文件
    S_IWOTH允许其他用户写文件
    S_IXOTH允许其他用户执行文件
    S_IRWXO允许其他用户读、写、执行文件
    S_ISUIDset-user-ID(特殊权限)
    S_ISGIDset-group-ID(特殊权限)
    S_ISVTXsticky(特殊权限)

    mode可直接使用数字型,xxxx(S-U-G-O),方便些

  • close(文件描述符)

    #include <unistd.h>
    
    int close(int fd);
    
  • read(文件描述符,首地址,读取大小),每次读是从内核缓冲区读取的

    #include <unistd.h>
    
    ssize_t read(int fd, void *buf, size_t count);
    
  • write(文件描述符, 首地址,写入大小),先写入内核缓冲区

    #include <unistd.h>
    
    ssize_t write(int fd, const void *buf, size_t count);
    
  • lseek(文件描述符,偏移量,参照位置)

    #include <sys/types.h>
    #include <unistd.h>
    
    off_t lseek(int fd, off_t offset, int whence);
    

    whence:

    • SEEK_SET: 文件头部
    • SEEK_CUR: 当前位置
    • SEEK_END: 文件结尾
  • fcntl()

    #include<unistd.h>
    #include<fcntl.h>
    
    int fcntl(int fd, int cmd, .../* arg */) 
    

    fd:文件描述符。
    cmd:操作命令。此参数表示我们将要对 fd 进行什么操作,cmd 参数支持很多操作命令,可以打开 man 手册查看到这些操作命令的详细介绍,这些命令都是以 F_XXX 开头的,譬如 F_DUPFD、F_GETFD、F_SETFD 等,不同的 cmd 具有不同的作用,cmd 操作命令大致可以分为以下 5 种功能:

    • 复制文件描述符(cmd=F_DUPFD 或 cmd=F_DUPFD_CLOEXEC);
    • 获取/设置文件描述符标志(cmd=F_GETFD 或 cmd=F_SETFD);文件权限标志(O_RDONLY、O_WRONLY、O_RDWR)以及文件创建标志(O_CREAT、O_EXCL、O_NOCTTY、O_TRUNC)不能被设置、会被忽略;
    • 获取/设置文件状态标志(cmd=F_GETFL 或 cmd=F_SETFL);
    • 获取/设置异步 IO 所有权(cmd=F_GETOWN 或 cmd=F_SETOWN);
    • 获取/设置记录锁(cmd=F_GETLK 或 cmd=F_SETLK);

其他知识点

  • fsync(), 将参数fd所指的文件内容和元数据写入磁盘。
        #include <unistd.h>
        
      int fsync(int fd);
    
  • fdatasync(), 将参数fd所指的文件内容写入磁盘,
    	#include <unistd.h>
    	
     int fdatasync(int fd);
    
  • sync(), 将所有的文件IO内核缓冲区的文件内容数据和元数据更新到磁盘。
    #include <unistd.h>
   void sync(void);
  • 以上所介绍的文件IO操作函数发生错误时会返回错误返回值-1。但我们并不能知道具体是啥错误,可喜的是以上函数发生错误时,系统会将一个全局变量errno置为错误代码(需要头文件<errno.h>)。但它任然是一个错误代码,需要去查资料解析他的意思。有二个个函数可以帮我们解析,

    • char *strerror(int errno), 返回对应错误的字符指针(<sting.h>)
    • void perror(char *s), 直接答应错误,不需要传递参数errno,需要传递补充的提示信息(可不传)(<stdio.h>)
  • 空洞文件, 当lseek()到大于该文件的位置是也是可以读写的,不会报错(应用: 多线程同时操作文件,就像修公路一样,每个队伍修一部分)。但前后之间的不会占用实际物理空间。但在计算文件大小时是算在内的。

  • 对同一个文件,可打开多次,但内核的缓冲区只有一个(动态文件)。静态文件:存储在硬件设备如磁盘,U盘等等存储设备。对于这些的读取是以块为单位的(一般为4K),也就是说不能单个字节单个字节的操作,故使用动态文件的方式即可加快读取时间,也可单个字节的方式操作文件。

  • 复制文件描述符(文件表没有复制
    在这里插入图片描述

    • int dup(int fd), 返回新的文件描述符,但文件表是同一个,
    • int dup2(int fd, int new_fd), new_fd为用户指定的新的描述符,如果已经存在就找一个比它的文件数字,返回新的文件描述符。
  • 文件共享问题
    当多个进程(线程)访问同一个文件时会出现竞争冒险的问题,因为进程的调度是不确定的,所以需要原子操作(将多个步骤合为一体,我猜是其内部实现了禁用中断,禁用调度器的调度)

    • O_APPEND, 将移动指针到末尾和写入数据组成了原子操作
    • O_EXCL|O_CREAT, 将检测文件是否存在和建立文件组成了原子操作
    • 函数,读写操作和偏移指针位置组成原子操作
      #include <unistd.h>
      
      ssize_t pread(int fd, void *buf, size_t count, off_t offset);
      ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
      
  • 直接IO读写: 绕过内核缓冲, mode加上O_DIRECT(还需要定义一个宏定义_GUN_SOURCE). eg:

     #define _GNU_SOURCE
      static char buf[8192] __attribute((aligned (4096)));  // 对齐
      fd = open(filepath, O_WRONLY|O_DIRECT);
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值