fcntl函数,fcntl 模拟dup和dup2,fcntl补设O_APPEND文件状态标志(文件IO)【linux】(m)

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是一个杂物箱,根据设置参数的不同,有很多种不同的功能,如果没有特定使用环境作为支撑的话,这个函数理解起来不太易,因此在这里,我们先记住有这么一个函数,有关它的使用,等后面涉及到了具体应用环境时,再来具体说明。

发布了84 篇原创文章 · 获赞 71 · 访问量 9106

猜你喜欢

转载自blog.csdn.net/qq_43648751/article/details/104175671