Linux文件IO(十)-fcntl 和 ioctl

news/2024/11/16 23:13:29/

本小节给大家介绍两个新的系统调用:fcntl()和 ioctl()。

fcntl 函数

fcntl()函数可以对一个已经打开的文件描述符执行一系列控制操作,譬如复制一个文件描述符(与 dup、dup2 作用相同)、获取/设置文件描述符标志、获取/设置文件状态标志等,类似于一个多功能文件描述符管理工具箱。fcntl()函数原型如下所示(可通过"man 2 fcntl"命令查看):

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

 函数参数和返回值含义如下:

fd:文件描述符。

cmd:操作命令。此参数表示我们将要对 fd 进行什么操作,cmd 参数支持很多操作命令,大家可以打开 man 手册查看到这些操作命令的详细介绍,这些命令都是以 F_XXX 开头的,譬如 F_DUPFD、F_GETFD、F_SETFD 等,不同的 cmd 具有不同的作用,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);

这里列举出来,并不需要全部学会每一个 cmd 的作用,因为有些内容并没有给大家提及到,譬如什么异步 IO、锁之类的概念,在后面的学习过程中,当学习到相关知识内容的时候再给大家介绍。

…:fcntl 函数是一个可变参函数,第三个参数需要根据不同的 cmd 来传入对应的实参,配合 cmd 来使用。

返回值:执行失败情况下,返回-1,并且会设置 errno;执行成功的情况下,其返回值与 cmd(操作命令)有关,譬如 cmd=F_DUPFD(复制文件描述符)将返回一个新的文件描述符、cmd=F_GETFD(获取文件描述符标志)将返回文件描述符标志、cmd=F_GETFL(获取文件状态标志)将返回文件状态标志等。

fcntl 使用示例

(1)复制文件描述符

前面给大家介绍了 dup 和 dup2,用于复制文件描述符,除此之外,我们还可以通过 fcntl 函数复制文件描述符, 可用的 cmd 包 括 F_DUPFD 和 F_DUPFD_CLOEXEC , 这 里 就 只 介 绍 F_DUPFD ,

F_DUPFD_CLOEXEC 暂时先不讲。

当 cmd=F_DUPFD 时,它的作用会根据 fd 复制出一个新的文件描述符,此时需要传入第三个参数,第三个参数用于指出新复制出的文件描述符是一个大于或等于该参数的可用文件描述符(没有使用的文件描述符);如果第三个参数等于一个已经存在的文件描述符,则取一个大于该参数的可用文件描述符。

测试代码如下所示:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.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, 0);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 打印出来,接下来编译运行:

可知复制得到的文件描述符是 7,因为在执行 fcntl 函数时,传入的第三个参数是 0,也就时指定复制得到的新文件描述符必须要大于或等于 0,但是因为 0~6 都已经被占用了,所以分配得到的 fd 就是 7;如果传入的第三个参数是 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 这些标志可以被修改,这里面有些标志并没有给大家介绍过,后面我们在用到的时候再给大家介绍。所以对于一个已经打开的文件描述符,可以通过这种方式添加或移除标志。

测试代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.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 标志。接下来编译测试:

 以上给大家介绍了 fcntl 函数的两种用法,除了这两种用法之外,还有其它多种不同的用法,这里暂时先不介绍了,后面学习到相应知识点的时候再给大家讲解。

ioctl 函数

ioctl()可以认为是一个文件 IO 操作的杂物箱,可以处理的事情非常杂、不统一,一般用于操作特殊文件或硬件外设,此函数将会在进阶篇中使用到,譬如可以通过 ioctl 获取 LCD 相关信息等,本小节只是给大家引出这个系统调用,暂时不会用到。此函数原型如下所示(可通过"man 2 ioctl"命令查看):

#include <sys/ioctl.h>int ioctl(int fd, unsigned long request, ...);

 使用此函数需要包含头文件<sys/ioctl.h>。

函数参数和返回值含义如下:

fd:文件描述符。

request:此参数与具体要操作的对象有关,没有统一值,表示向文件描述符请求相应的操作

...:此函数是一个可变参函数,第三个参数需要根据 request 参数来决定,配合 request 来使用。

返回值:成功返回 0,失败返回-1。


http://www.ppmy.cn/news/1531701.html

相关文章

企业数据可视化大屏的工具选择有哪些

数据作为企业的核心的资产已经越发的受到企业管理层的关注&#xff0c;数据不仅作为企业日常经营做出决策的重要依据&#xff0c;同时更是推动企业进行变革的核心&#xff0c;那么更好的利用数据以及解读各类数据报表就是最为核心的&#xff0c;所以也就带来了数据可视化的产品…

CentOS8.5.2111(3)实验之DHCP服务器架设

一、实验目标 1&#xff0e;掌握DHCP服务器的主配置文件各项申明参数及操作及其含义 2. 具备DHCP 服务器、中继服务器的配置能力 3. 具备测试客户端正常获取服务器分配地址的能力 4. 具备DHCP服务器故障排除能力 二、实训原理/流程 &#xff08;一&#xff09;项目背景 …

iOS 提取图片的主题色,并支持灵活提取

遇到一个需求&#xff0c;要提取图片中的色调&#xff0c;但还有一点特殊的需求&#xff0c;就是不是提取颜色最多的色调&#xff0c;也不是平均的色调&#xff0c;是图片中偏暗的色调 这就需要我们动态的调整我们提取的算法&#xff0c; 下面就看代码 dispatch_async(dispatch…

GO Serial 学习与使用

文章目录 主要特性安装基本用法配置选项错误处理其他功能 github.com/goburrow/serial 是一个 Go 包&#xff0c;提供了一种简单的方式来与串口进行交互。以下是该包的主要特性和用法的简要概述&#xff1a; 主要特性 跨平台支持&#xff1a;支持 Windows、macOS 和 Linux。简…

【电商搜索】现代工业级电商搜索技术-Ha3搜索引擎平台简介

【电商搜索】现代工业级电商搜索技术-Ha3搜索引擎平台简介 — 初稿V1.0 Ha3搜索引擎平台详细介绍 在当今的互联网时代&#xff0c;搜索引擎扮演着至关重要的角色&#xff0c;尤其是在电子商务领域。Ha3搜索引擎平台是由阿里巴巴搜索团队开发的一个先进的搜索引擎&#xff0c…

MySQL 之多表设计详解

在实际应用场景中&#xff0c;我们经常需要处理包含多种数据实体及其之间复杂关系的业务逻辑&#xff0c;例如电商平台的用户、商品、订单&#xff0c;社交网络的用户、帖子、评论等等。如果将所有数据都堆砌在一张表中&#xff0c;不仅会造成数据冗余、难以维护&#xff0c;还…

学Python再学C++是走弯路?

随着编程教育的普及&#xff0c;越来越多的家长和学生开始选择学习编程语言。Python作为一种简洁易学、应用广泛的编程语言&#xff0c;成为许多编程初学者的首选。然而&#xff0c;随着学习的深入&#xff0c;很多人会考虑转向更复杂、更底层的语言&#xff0c;如C。这就引发了…

小白投资理财 - 证券开户

小白投资理财 - 证券开户 前言股票交易费用计算示例名词解释&#xff1a;佣金&#xff0c;印花税&#xff0c;过户费佣金印花税过户费 开户开户前准备开户流程开户完成后注意事项 前言 开通证券账户是投资者进入金融市场、进行各种投资活动的前提条件。作为小白&#xff0c;先…