fcntl()
函数可以对一个已经打开的文件描述符执行一系列控制操作,譬如复制一个文件描述符(与
dup
、 dup2 作用相同)、获取
/
设置文件描述符标志、获取
/
设置文件状态标志等,类似于一个多功能文件描述符管理工具箱。
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ )
fd
:
文件描述符。
cmd
:
操作命令。此参数表示我们将要对
fd 进行什么操作,cmd 操作命令大致可以分为以下 5 种功能:
⚫
复制文件描述符(
cmd=F_DUPFD
或
cmd=F_DUPFD_CLOEXEC
);
⚫
获取
/
设置文件描述符标志(
cmd=F_GETFD
或
cmd=F_SETFD
);
⚫
获取
/
设置文件状态标志(
cmd=F_GETFL
或
cmd=F_SETFL
);
⚫
获取
/
设置异步
IO
所有权(
cmd=F_GETOWN
或
cmd=F_SETOWN
);
⚫
获取
/
设置记录锁(
cmd=F_GETLK
或
cmd=F_SETLK);
(2) 获取 /设置文件状态标志
…:
fcntl
函数是一个可变参函数,第三个参数需要根据不同的
cmd
来传入对应的实参,配合
cmd
来使 用。
返回值:
执行失败情况下,返回
-1
,并且会设置
errno
;执行成功的情况下,其返回值与
cmd
(操作命 令)有关,譬如 cmd=F_DUPFD
(复制文件描述符)将返回一个新的文件描述符、
cmd=F_GETFD
(获取文 件描述符标志)将返回文件描述符标志、cmd=F_GETFL
(获取文件状态标志)将返回文件状态标志等。
fcntl 使用示例
(1)复制文件描述符
(1)复制文件描述符
当
cmd=F_DUPFD
时,它的作用会根据
fd
复制出一个新的文件描述符,此时需要传入第三个参数,第 三个参数用于指出新复制出的文件描述符是一个大于或等于该参数的可用文件描述符(没有使用的文件描 述符);如果第三个参数等于一个已经存在的文件描述符,则取一个大于该参数的可用文件描述符。
示例代码:
示例代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int fd1, fd2;
int ret;
/* 打开文件 test_file */
fd1 = open("./test_file", O_RDONLY);
if (-1 == fd1)
{
perror("open error");
exit(-1);
}
/* 使用 fcntl 函数复制一个文件描述符 */
fd2 = fcntl(fd1, F_DUPFD, 100);
if (-1 == fd2)
{
perror("fcntl error");
ret = -1;
goto err;
}
printf("fd1: %d\nfd2: %d\n", fd1, fd2);
ret = 0;
close(fd2);
err:
/* 关闭文件 */
close(fd1);
exit(ret);
}
在当前目录下存在
test_file
文件,上述代码会打开此文件,得到文件描述符
fd1
,之后再使用
fcntl
函数 复制 fd1
得到新的文件描述符
fd2
,并将
fd1
和
fd2
打印出来。
编译测试:
![](https://i-blog.csdnimg.cn/blog_migrate/c0c0b931326bdace734906a6285c5352.png)
可知复制得到的文件描述符是
7
,因为在执行
fcntl
函数时,传入的第三个参数是
0,也就时指定复制得到的新文件描述符必须要大于或等于 100,那么
fd2
就会等于
100。
(2) 获取 /设置文件状态标志
cmd=F_GETFL
可用于获取文件状态标志,
cmd=F_SETFL
可用于设置文件状态标志。
cmd=F_GETFL
时 不需要传入第三个参数,返回值成功表示获取到的文件状态标志;cmd=F_SETFL
时,需要传入第三个参数, 此参数表示需要设置的文件状态标志。
这些标志指的就是我们在调用
open
函数时传入的
flags
标志,可以指定一个或多个(通过位或
|
运算符组合),但是文件权限标志(O_RDONLY
、
O_WRONLY
、
O_RDWR
)以及文件创建标志(
O_CREAT
、 O_EXCL、
O_NOCTTY
、
O_TRUNC
)不能被设置、会被忽略;在
Linux
系统中,只有
O_APPEND
、
O_ASYNC、O_DIRECT
、
O_NOATIME
以及
O_NONBLOCK 这些标志可以被修改。
对于一个已经打开的文件描述符,可以通过这种方式添加或移除标志。
示例代码:fcntl 读取/设置文件状态标志
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int fd;
int ret;
int flag;
/* 打开文件 test_file */
fd = open("./test_file", O_RDWR);
if (-1 == fd)
{
perror("open error");
exit(-1);
}
/* 获取文件状态标志 */
flag = fcntl(fd, F_GETFL);
if (-1 == flag)
{
perror("fcntl F_GETFL error");
ret = -1;
goto err;
}
printf("flags: 0x%x\n", flag);
/* 设置文件状态标志,添加 O_APPEND 标志 */
ret = fcntl(fd, F_SETFL, flag | O_APPEND);
if (-1 == ret)
{
perror("fcntl F_SETFL error");
goto err;
}
ret = 0;
err:
/* 关闭文件 */
close(fd);
exit(ret);
}
上述代码会打开
test_file
文件,得到文件描述符
fd
,之后调用
fcntl(fd, F_GETFL)
来获取到当前文件状态标志 flag
,并将其打印来;接着调用
fcntl(fd, F_SETFL, flag | O_APPEND)
设置文件状态标志,在原标志的基础上添加 O_APPEND
标志。
编译测试:
![](https://i-blog.csdnimg.cn/blog_migrate/504c1517f50425c79093430c5e97b171.png)