为什么要使用fcntl函数
假设我们已经打开了一个文件,那么
当我想修改已打开文件的属性
时,就可以利用fcntl函数直接改变已打开文件的属性
,而不用关闭然后重新打开来设置
。
fcntl函数
原型:
当第二个参数取不同的值时,fcntl有不同的功能:
cmd=F_DUPFD或F_DUPFD_CLOEXEC
:复制
一个已有的描述符,返回新的
文件描述符
cmd=F_GETFD或F_SETFD
:获取/设置文件描述符
标志
cmd=F_GETFL或F_SETFL
:获取文件状态
标志(如O_RDONLY、O_WRONLY、O_RDWR等,这三个值互斥
,一个文件的访问方式只能取这几个值之一
,因此需要用屏蔽字O_ACCMODE取得访问方式位
,然后与这几个值比较)。设置文件状态时将文件状态标志设置为第三个参数的值(可更改的几个标志
:O_APPEND
、O_NONBLOCK
等)
cmd=F_GETOWN或F_SETOWN
:获取/设置异步IO所有权
:即获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。设置接收SIGIO和SIGURG信号的进程ID或进程组ID
cmd=F_GETLCK或F_SETLK或F_SETLKW
:获取/设置记录锁
fcntl使用示例
示例1:获取文件hello的状态标志
/// for read()
#include <unistd.h>
/// for open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/// for exit()
#include <stdlib.h>
#define BUFFERSIZE 1024
int main(int argc, char *argv[]) {
int ret;
int fd = atoi(argv[1]);
if ((ret = fcntl(fd, F_GETFL)) < 0) {
perror("fcntl() error!");
exit(1);
}
switch (ret & O_ACCMODE) {
case O_RDONLY:
puts("O_RDONLY");break;
case O_WRONLY:
puts("O_WRONLY");break;
case O_RDWR:
puts("O_RDWR");break;
default:
break;
}
if(ret & O_APPEND)
puts("O_APPEND");
if(ret & O_NONBLOCK)
puts("O_NONBLOCK");
if(ret & O_TRUNC)
puts("O_TRUNC");
return 0;
}
示例2:修改状态标志的正确方式
首先要获得现在的标志值,然后按照期望修改它,最后才是设置新的标志值
。
如果只是执行F_SETFD或F_SETFL,这样会关闭以前的标志位
示例中的ret |= flags
用于设置flags标志
如果是ret &= ~flags
则用于取消flags标志
void set_fl(int fd, int flgs) {
int ret;
if ((ret = fcntl(fd, F_GETFL)) < 0)
perror("fcntl() error!");
ret |= flags; /// turn on flags
if (fcntl(fd, F_SETFL, ret) < 0)
perror("fcntl() error!");
}