Linux fcntl函数怎么用?一文详解文件控制操作

 更新时间:2026年09月05日 14:07:56   作者:妙缘12138  
本文详细讲解Linux系统调用fcntl函数的用法,包括改变文件性质、设置文件锁、追加写入及非阻塞管道等操作,通过代码示例帮助你掌握文件控制技巧

如果,想要深入的学习Linux系统调用中的fcntl函数,还是需要去自己阅读Linux系统中的帮助文档。

具体输入命令:

man 2 fcntl

即可查阅到完整的资料信息。

fcntl函数

fcntl函数是Linux系统API中的一员,它的主要有以下几个作用:

  1. 改变已经打开的文件性质.
  2. 类似 dup 的功能。
  3. 改变文件的文件状态标志(fl_flags)。
  4. 得到或设置文件锁记录。

在这篇文章中,我们主要介绍功能前1和3。

它的函数原型是长这样的:

int fcntl(int fd, int cmd, …);

接下来,我来介绍一下它的多个参数与返回值

    参数:
    fd : 表示需要操作的文件描述符
    cmd: 表示对文件描述符进行如何操作(一些系统定义宏值)
        - F_DUPFD : 复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)
            int ret = fcntl(fd, F_DUPFD);

        - F_GETFL : 获取指定的文件描述符文件状态flag
          获取的flag和我们通过open函数传递的flag是一个东西。

        - F_SETFL : 设置文件描述符文件状态flag
          必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
          可选性:O_APPEND, O)NONBLOCK
            O_APPEND 表示追加数据
            NONBLOK 设置成非阻塞
    ... :可变参数,看需求添加。
    阻塞和非阻塞:描述的是函数调用的行为。

在使用这个函数之前,我们需要往C/C++文件中导入这些头文件:

#include <unistd.h>
#include <fcntl.h>

下面我来通过一个例子,来演示一下这个函数的具体作用:

代码演示:往已经存在的文件里追加数据

/*
    子进程向父进程发送信息
    设置管道非阻塞
    int flags = fcntl(fd[0], F_GETFL);  // 获取原来的flag
    flags |= O_NONBLOCK;            // 修改flag的值
    fcntl(fd[0], F_SETFL, flags);   // 设置新的flag
*/

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    int fd[2] ;
    int ret = pipe(fd);
    if(ret == -1){
        perror("pipe");
        exit(0);
    }

    pid_t pid = fork();
    
    int flags = fcntl(fd[0],F_GETFL); //获取原来文件描述符标志信息
    flags |= O_NONBLOCK;//给原来的文件描述符标志信息中添加非阻塞的标志信息
    fcntl(fd[0],F_SETFL,flags);//设置新的标志信息

    if(pid > 0){ 
        close(fd[1]);//只读不写,关闭写端
        

        char buf[1024];
        while (1)
        {
            sleep(2);
            printf("这里是父进程,我的pid是:%d,正在接受来自子进程的信息...\n",getpid());
            int len = read(fd[0],buf,sizeof(buf)-1);
            printf("len: %d , %s\n", len, buf);
            memset(buf,0,1024);
        }
        

    }else if(pid == 0){
        close(fd[0]);//只写不读,关闭读端

        while(1){
            printf("这里是子进程,我的pid是:%d,正在向父进程发送数据...\n",getpid());
            char buf[] = "hello,i am child";
            write(fd[1],buf,sizeof(buf));
            sleep(10);
        }

    }else{
        perror("fork");
        return -1;
    }
    return 0; 
}

有些人可能会问,我明明已经有写的权限了,我为什么不直接用write函数往文件里写文件。而先要用fcntl去追加权限呢?

这是因为如果你只有写的权限的话,你直接写就是把原来文件里的数据完全覆盖掉。而有O_APPEND权限则是可以在原来文件的末尾处添加数据,而不是覆盖了。

代码演示

将管道的文件描述符改为非阻塞,父进程读取子进程写入的数据:

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
/*
    设置管道非阻塞
    int flags = fcntl(fd[0], F_GETFL);  // 获取原来的flag
    flags |= O_NONBLOCK;            // 修改flag的值
    fcntl(fd[0], F_SETFL, flags);   // 设置新的flag
*/
int main() {

    // 在fork之前创建管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret == -1) {
        perror("pipe");
        exit(0);
    }

    // 创建子进程
    pid_t pid = fork();
    if(pid > 0) {
        // 父进程
        printf("i am parent process, pid : %d\n", getpid());

        // 关闭写端
        close(pipefd[1]);
        
        // 从管道的读取端读取数据
        char buf[1024] = {0};

        int flags = fcntl(pipefd[0], F_GETFL);  // 获取原来的flag
        flags |= O_NONBLOCK;            // 修改flag的值
        fcntl(pipefd[0], F_SETFL, flags);   // 设置新的flag

        while(1) {
            int len = read(pipefd[0], buf, sizeof(buf));
            printf("len : %d\n", len);
            printf("parent recv : %s, pid : %d\n", buf, getpid());
            memset(buf, 0, 1024);
            sleep(1);
        }

    } else if(pid == 0){
        // 子进程
        printf("i am child process, pid : %d\n", getpid());
        // 关闭读端
        close(pipefd[0]);
        char buf[1024] = {0};
        while(1) {
            // 向管道中写入数据
            char * str = "hello,i am child";
            write(pipefd[1], str, strlen(str));
            sleep(5);
        }
        
    }
    return 0;
}

输出结果:

nowcoder@nowcoder:~/Linux/lession22$ ./noblock1 
这里是子进程,我的pid是:24822,正在向父进程发送数据...
这里是父进程,我的pid是:24821,正在接受来自子进程的信息...
len: 17 , hello,i am child
这里是父进程,我的pid是:24821,正在接受来自子进程的信息...
len: -1 , 
这里是父进程,我的pid是:24821,正在接受来自子进程的信息...
len: -1 , 
这里是父进程,我的pid是:24821,正在接受来自子进程的信息...
len: -1 ,
^c

因为我们将这个管道的读端这个文件描述符改为了非阻塞的。所以当父进程循环的时候,如果管道中没有数据,read函数不会阻塞在那里,而是会直接返回-1。也就是表示读取失败。紧接着printf继续输出内容。不会停止下来。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • linux下如何创建守护进程的步骤

    linux下如何创建守护进程的步骤

    本篇文章主要介绍了linux下如何创建守护进程的步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • Linux chage命令详解

    Linux chage命令详解

    chage命令用于密码实效管理,该是用来修改帐号和密码的有效期限,接下来通过本文给大家介绍Linux chage命令相关知识,本文介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-01-01
  • linux使用nginx部署ssl证书,将http升级为https实现方式

    linux使用nginx部署ssl证书,将http升级为https实现方式

    本文详细介绍了在CentOS Stream 8上使用Nginx部署Vue和React项目的步骤,包括下载SSL证书、上传证书、安装SSL模块、验证安装以及配置nginx.conf文件
    2026-03-03
  • Linux系统中jdk环境配置方式

    Linux系统中jdk环境配置方式

    这篇文章主要介绍了Linux系统中jdk环境配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 如何设置linux centos7连接网络

    如何设置linux centos7连接网络

    这篇文章主要介绍了如何设置linux centos7连接网络问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Linux 中如何切换相同程序的不同版本

    Linux 中如何切换相同程序的不同版本

    这篇文章主要介绍了 Linux 中如何切换相同程序的不同版本,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • Linux磁盘检测、修复与备份恢复的详细指南

    Linux磁盘检测、修复与备份恢复的详细指南

    本文详细介绍了Linux系统中磁盘检测与修复、文件系统备份与恢复以及XFS文件系统的维护工具,内容涵盖工具的功能、基本语法、常用选项和使用示例,同时提供了实战案例和最佳实践建议,旨在帮助系统管理员有效地管理和维护存储系统,需要的朋友可以参考下
    2025-12-12
  • Linux报错:tar: Error Is Not Recoverable: Exiting Now问题及解决

    Linux报错:tar: Error Is Not Recoverable:&n

    本文介绍了在Linux系统下解压`.tar.gz`文件时遇到的错误及其解决方法,错误通常是由于文件下载不完整或参数设置错误引起的,解决方法包括:1. 去掉解压参数中的`z`,改为`tar -xvf xx.tar.gz`,适合非gzip过滤归档文件;2. 重新下载或上传文件,确保文件完整性
    2025-02-02
  • linux查看服务器开放的端口和启用的端口多种方式

    linux查看服务器开放的端口和启用的端口多种方式

    Nmap可以扫描网络中的处于活动状态的主机、开放端口、操作系统版本和服务检测以及执行隐匿方式的信息扫描,这篇文章主要介绍了linux查看服务器开放的端口和启用的端口五种方式,需要的朋友可以参考下
    2022-08-08
  • Linux统计某个字符串出现次数并排序的实现步骤

    Linux统计某个字符串出现次数并排序的实现步骤

    最近遇到一个流量异常调用的接口,所以需要通过后台日志查看接口调用情况,先统计今天内接口的调用次数,再具体到对应的设备号,所以本文给大家介绍了Linux统计某个字符串出现次数并排序的实现步骤,需要的朋友可以参考下
    2024-07-07

最新评论