fcntl函数,fcntl 模拟dup和dup2,fcntl补设O_APPEND文件状态标志
fcntl函数
我们可以通过帮助手册查看fcntl函数的详细信息:
函数原型
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
我们可以看到,在函数参数有: … /* arg */ 的形式说明函数参数有时候使用,有的时候不使用。
功能
fcntl函数是File Control的缩写,通过fcntl可以设置、或者修改已打开的文件性质。
返回值
调用成功:返回值视具体参数而定,这个后面还会再介绍
调用失败:返回-1,并把错误号设置给errno。
参数
int fcntl(int fd, int cmd, … /* arg */ );
1)fd:指向打开文件
2)cmd:控制命令,通过指定不同的宏来修改fd所指向文件的性质。(a)F_DUPFD
复制描述符,可用来用来模拟dup和dup2,后面会有例子对此用法进行说明。
返回值:返回复制后的新文件描述
(b)F_GETFL、F_SETFL
获取、设置文件状态标志,比如在open时没有指定O_APPEND,可以使用fcntl函数来补设。
返回值:返回文件的状态.
fcntl来补设文件状态标志
当文件描述符不是你自己open得到,而是调用别人给的函数,别人的函数去open某个文件,然后再将文件描述符返回给你用,在这种情况下,我们是没办法去修改被人的函数,在他调用的open函数里补加文件状态标志。此时就可以使用fcntl来布设了,使用fcntl补设时,你只需要知道文件描述符即可。
c、d、e这三种情况,后面课程中具体涉及到后,再来详细介绍如何。
(c)F_GETFD、F_SETFD
(d)F_GETOWN、F_SETOWN
(e)F_GETLK或F_SETLK或F_SETLKW
fcntl 模拟dup和dup2
不过,我们真要进行文件描述符复制时,往往都使用dup、dup2来实现,而不会使用fcntl,这里使用fcntl来模拟dup、dup2,完全是为了向读者演示一下,fcntl这个函数是怎么用的。
模拟dup
执行结果为:
我们可以看到写入成功,打开的文件里面写入了hello world
模拟dup2
执行结果为:
我们可以看到写入成功。
fcntl补设O_APPEND文件状态标志
我们先写用多次open来达到文件共享的操作:
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
int open_fun1(void)
{
int fd = 0;
fd = open("./new.txt",O_RDWR);
if(-1 == fd)
{
printf("open fail\n",errno);
}
return fd;
}
int open_fun2(void)
{
int fd = 0;
fd = open("./new.txt",O_RDWR);
if(-1 == fd)
{
printf("open fail\n",errno);
}
return fd;
}
int main(void)
{
int fd1 = 0;
int fd2 = 0;
fd1 = open_fun1();
fd2 = open_fun2();
while(1)
{
write(fd1,"hello\n",6);
sleep(2);
write(fd2,"world\n",6);
}
return 0;
}
执行结果为 :
我们可以看到执行成功并且hello被world覆盖。
现在我们要解决覆盖的问题但是现在如果这个函数是别人写的,我们就无法进入到函数内部去修改文件的操作方式。所以就是用fcntl 函数进行补设O_APPEND文件状态标志,我们给出代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int open_fun1(void)
{
int fd = open("./new.txt", O_RDWR);
if(-1 == fd)
{
printf("open fail: %d\n", errno);
return 0;
}
return fd;
}
int open_fun2(void)
{
int fd = open("./new.txt", O_RDWR);
if(-1 == fd)
{
printf("open fail: %d\n", errno);
return 0;
}
return fd;
}
int main(void)
{
int fd1 = 0;
int fd2 = 0;
int flag = 0;
fd1 = open_fun1();
fd2 = open_fun2();
/* 直接制定F_SETFL时,会直接使用新的标志,去修改掉就的标志
返回的是新设置的标志
*/
flag = O_WRONLY|O_TRUNC|O_APPEND;
fcntl(fd1, F_SETFL, flag);
/* 保留原有标志,然后在原有标志的基础上,叠加新标志 */
flag = fcntl(fd2, F_GETFL, 0);//获取原有标志
flag = flag | O_TRUNC | O_APPEND;//叠加
fcntl(fd2, F_SETFL, flag); //设置回去
while(1)
{
write(fd1, "hello\n", 6);
sleep(1);
write(fd2, "world\n", 6);
}
return 0;
}
执行结果为:
我们可以看到没有覆盖,说明补设O_APPEND文件状态标志成功。
ioctl函数提出
在某些特殊的情况下,使用read、write、lseek函数进行文件io(读写)操作时,存在一定的问题,此时往往就是使用ioctl函数,来实现这些比较特殊情况的io操作。
ioctl是一个杂物箱,根据设置参数的不同,有很多种不同的功能,如果没有特定使用环境作为支撑的话,这个函数理解起来不太易,因此在这里,我们先记住有这么一个函数,有关它的使用,等后面涉及到了具体应用环境时,再来具体说明。
来源:CSDN
作者:熟练的初学者
链接:https://blog.csdn.net/qq_43648751/article/details/104175671