Linux文件IO(十)-fcntl 和 ioctl

embedded/2024/9/24 19:43:14/

本小节给大家介绍两个新的系统调用: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/embedded/116234.html

相关文章

前端html+css+js 基础总结

​​​HTML 行级元素 标签分为行级元素与块级元素 行级元素占据区域由其显示内容决定&#xff0c;如span&#xff0c;img(图片)&#xff0c;<a></a>基本格式: <a href"链接" target"_blank"></a>用于跳转到其他网站&#xff0c…

微服务_入门2

文章目录 一、Feign远程调用二、Gateway服务网关2.1、为什么需要网关2.2、gateway快速入门2.3、断言工厂2.4、过滤器 一、Feign远程调用 来看我们以前利用RestTemplate发起远程调用的代码&#xff1a; 存在下面的问题&#xff1a; 代码可读性差&#xff0c;编程体验不统一&…

52.拼接数组

//定义一个方法&#xff0c;把int数组中的数据按照指定的格式拼接成一个字符串返回。 //调用该方法&#xff0c;并在控制台输出结果 //例如&#xff1a;数组为int[] arr{1,2,3}; //执行方法后的输出结果为&#xff1a;[1,2,3] public class 拼接数组 {public static void main…

[网络][知识]TCP-IP各协议的RFC编号和RFC原始文档的获取地址

TCP/IP协议族包括很多个子协议,下面是TCP/IP 协议和支持服务所支持的 RFC。 RFC768 用户数据报协议 (UDP) RFC783 简单文件传输协议 (TFTP) RFC791 Internet 协议 (IP) RFC792 Internet 控制消息协议 (ICMP) RFC793 传输控制协议 (TCP) RFC816 故障隔离和恢复 RFC…

python概述

目录 python语言的特点 python语言的优点&#xff1a; python语言的缺点&#xff1a; 1.常用的python编辑器 PyCharm Jupyter Notebook VScode 模块的安装、导入与使用 安装 导入与使用 python语言的特点 1.简洁 2.语法优美 3.简单易学 4.开源&#xff1a;用户可自…

在idea里运行swing程序正常,但是在外部运行jar包却报错,可能是jdk版本问题

在idea里运行swing程序异常&#xff0c;报Caused by: java.awt.HeadlessException错误 System.setProperty("java.awt.headless","false");加上这句话

误删系统引导如何恢复?如何创建系统引导?

Default Boot Device Missing or Boot Fai led.Insert Recovery Media and Hit any keyThen Select “Boot Manager’ to choose a new Boot Device or to Boot Recovery Media 一、事出原因&#xff1a; 同事强迫症格式化所有系统引导盘后&#xff0c;重装系统后无法开机问题…

vue-router路由(重定向,嵌套,动态路由匹配,命名,高亮,守卫)

一、前端路由的概念与原理 路由router就是对应关系。分为前端路由和后端路由。 1后端路由 后端路由指的是&#xff1a;请求方式、请求地址与function处理函数之间的对应关系。在node.js中&#xff0c;express理由的基本用法如下&#xff1a; const express require(expres…