当前位置: 首页 > news >正文

【Linux】文件描述符 fd

目录

一、C语言文件操作

1.1 fopen和fclose

1.2 fwrite和fread

1.3 C语言中的输入输出流

二、Linux的文件系统调用

2.1 open和文件描述符

2.2 close

2.3 read

2.4 write

三、Linux内核数据结构与文件描述符


一、C语言文件操作

在C语言中我们想要打开一个文件并对其进行读取写入等各种操作,需要依赖于fopen、fread、fwrite等函数。我们先来回顾一下这些函数

1.1 fopen和fclose

其中:

  • path:目标文件的路径
  • mode:文件的打开模式

文件的打开模式中,r表示只读,w表示只写,a表示追加,还有很多模式相信对大家来说都不陌生

fopen如果打开文件成功,会返回一个FILE*指针,其中FILE结构体是C库自己封装的结构体,内部封装了文件的各种属性

一个文件被打开后,如果我们不需要使用该文件了,就需要使用fclose关闭它,向函数传入先前从fopen接收到的FILE*指针即可。

1.2 fwrite和fread

其中:

  • ptr:指向某一内存块的指针
  • size:要读取/写入的元素大小
  • nmemb:要读取/写入的元素个数
  • stream:文件指针

所以读取或写入的字节总数为size*nmemb

我们可以用fwrite对一个文件进行写入,例如:

#include <stdio.h>
#include <string.h>int main()
{FILE *fp = fopen("myfile", "w");if(!fp){printf("fopen error!\n");}const char *str = "hello Linux\n";fwrite(str, strlen(str), 1, fp); fclose(fp);return 0;                                                                                                                                                                                                 
}            

运行代码,可以看到已经写入成功了

我们还可以用fread读取一个文件的内容,例如:

#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{FILE *fp = fopen("myfile", "r");                                                                                                                                                                          if(!fp){printf("fopen error!\n");}char buf[1024];ssize_t s = fread(buf, 1, sizeof(buf), fp);if(s){buf[s] = '\0';printf("%s", buf);}fclose(fp);return 0;
}

fread如果读取成功,会返回读取的元素总数,与nmemb个数相同

运行代码,可以发现之前写入到myfile文件中的内容已经被读取出来了

除了以上的这些接口,C语言还有很多的文件操作接口,这里不是重点不作过多赘述

1.3 C语言中的输入输出流

在Linux中一切皆文件,显示器也是文件,我们也可以对其进行写入操作

如何对其进行写入呢?这里介绍C语言中的三个输入输出流

其中stdin标准输入流,对应我们的键盘stdout标准输出流stderr标准错误流,这两个流对应我们的显示器。这三个输入输出流是C语言程序在启动时默认会给我们打开的

不止是C语言,其他语言也会默认打开这三个流,不过名称不同。C++中分别是cin、cout和cerr 

进程将从标准输入流中得到输入数据,将正常输出数据输出到标准输出流,而将错误信息送到标准错误流中

可以看到,这三个流的类型都是FILE*,也就是说我们自己也可以通过fread从标准输入流中读取键盘输入的内容,通过fwrite向标准输出流或标准错误流即显示器文件写入我们的内容。

#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{const char* str = "hello Linux\n";fwrite(str, 1, strlen(str), stdout);return 0;                                                                                                                                                                                                 
}

运行程序,可以看到我们已经把内容写入到显示器文件中了


二、Linux的文件系统调用

在前面了解操作系统的时候就提到,操作系统是有自己的系统调用接口的。

而语言中涉及到操作系统内核部分的函数,实际上都是封装了操作系统的系统调用接口,包括C语言的文件操作接口也是封装了操作系统的文件系统调用接口

所以我们先来了解一下Linux中的文件系统调用接口

2.1 open和文件描述符

open是Linux系统中用来打开文件的一个系统调用接口,其中:

  • pathname:目标文件的路径
  • flag:文件访问权限标志
  • mode:如果创建新文件,指定新建文件的访问权限

flag参数是文件访问权限标志位,其中:

  • O_RDONLY:以只读方式打开文件
  • O_WRONLY:以只写方式打开文件
  • O_RDWR:以可读可写方式打开文件

我们在使用open函数时必须包含以上三种中的一种标志位,除了这些还有其他的可选标志位,这里列出常用的三种:

  • O_CREAT:如果pathname指向的文件不存在则创建文件
  • O_TRUNC:打开文件的同时清空文件
  • O_APPEND:以追加方式对文件进行写入

标志位可以通过位运算的方式同时选中多种,例如:

像上面这样,就是以只写方式打开文件、以追加方式写入、如果文件不存在则创建

其中如果选中了O_CREAT,一般都要对mode参数进行设置,该参数用来设置新创建的文件权限

关于文件权限,我在前面的文章中有讲过

【Linux】常用指令、热键与权限管理-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Eristic0618/article/details/138795212?spm=1001.2014.3001.5501接下来我们看看open函数的返回值

可以看到,成功打开文件后open函数会返回一个file descriptor,即所谓的文件描述符(fd)

文件描述符是一个整型,从0开始向后分配,系统在给文件分配文件描述符时会分配当前没有被使用的最小的文件描述符 

关于文件描述符的本质,在后面会详细提到,目前只需要知道进程是通过文件描述符来访问文件的

2.2 close

close是Linux系统中关闭文件的系统调用接口,其参数就是一个文件描述符,传入文件对应的文件描述符即可关闭该文件

2.3 read

read函数将从fd对应的文件中读取count个字节到buf指向的内存块中

成功则返回读取到的字节数,失败则返回-1,若调用read时文件已达末尾则返回0

2.4 write

write函数将把buf指向的内存块中的内容写入count个字节到fd对应的文件中

成功则返回写入的字节数,失败则返回-1


三、Linux内核数据结构与文件描述符

到这里,相信大家已经学会如何使用Linux中的文件系统调用接口了,接下来我们深入探讨一下访问文件的本质

一个文件由内容属性两部分构成,没打开的文件存储在磁盘中,本文重点不在于未打开的文件所以不作过多探讨。而我们如果要打开一个文件,就先得将其加载到内存中,这是由冯·诺依曼体系结构决定的。

所以在操作系统内部一定存在着大量的被打开的文件,操作系统也自然要对这些文件进行管理,即先描述再组织。操作系统内部使用file结构体(与C语言的FILE结构体不同)来描述一个被打开文件的信息,其中包括该文件的基本属性、权限、大小、内核缓冲区信息等等,将这些结构体用数据结构组织起来,就可以完成对被打开文件的管理了。

而一个进程可以同时打开多个文件,所以进程和文件是一对多的关系。要把一个进程打开的所有文件管理起来,我们就要使用一个files_struct结构体

我们知道操作系统通过PCB描述进程,而在进程的PCB中就有这么一个类型为 struct files_struct* 的指针files指向了进程的files_struct结构体,其定义如下

struct files_struct {atomic_t count;struct fdtable *fdt;struct fdtable  fdtab;int next_fd;struct embedded_fd_set close_on_exec_init;struct embedded_fd_set open_fds_init;struct file * fd_array[NR_OPEN_DEFAULT];
};

其中的fd_array数组,就指向了进程打开的一个个文件的file结构体。很多人称files_struct是文件描述符表,但我认为这个fd_array数组才是更准确的文件描述符表,因为所谓的文件描述符,其实就是文件在这个表中存储位置的下标

前面提到,程序在启动时会默认打开三个标准输入输出流,所以文件描述符表中的前三个位置是默认被使用的。对应的,标准输入流的文件描述符为0,标准输出流的文件描述符为1,标准错误流的文件描述符为2

如何验证?在C语言中文件的属性被封装在FILE结构体中,结构体中的_fileno就是文件的文件描述符,我们只需要把三个标准流的文件描述符打印出来就能验证了

int main()
{printf("stdin:%d\n", stdin->_fileno);printf("stdout:%d\n", stdout->_fileno);printf("stderr:%d\n", stderr->_fileno);                                                                                                                                                                   return 0;
}

可以看到三个标准流对应的文件描述符就是0、1、2

如果此时我们在打印前close(1),会发生什么呢?

int main()
{close(1);printf("stdin:%d\n", stdin->_fileno);printf("stdout:%d\n", stdout->_fileno);printf("stderr:%d\n", stderr->_fileno);                                                                                                                                                                   return 0;
}

什么也不会打印,因为标准输出流即显示器文件在打印前已经被关闭了

我们可以在程序中打开多个文件,看看它们的文件描述符是什么

int main()
{int fd1 = open("file1", O_WRONLY|O_TRUNC|O_CREAT, 0666);int fd2 = open("file2", O_WRONLY|O_TRUNC|O_CREAT, 0666);int fd3 = open("file3", O_WRONLY|O_TRUNC|O_CREAT, 0666);int fd4 = open("file4", O_WRONLY|O_TRUNC|O_CREAT, 0666);printf("fd1:%d\n", fd1);printf("fd2:%d\n", fd2);printf("fd3:%d\n", fd3);printf("fd4:%d\n", fd4);                                                                                                                                                                                  return 0;
}

可以看到,系统会给文件分配当前未被使用的最小的文件描述符

一个文件可以被多个进程打开,那么是不是一个进程将该文件关闭了,该文件对应的资源就要被系统回收呢?

不是的,在file结构体中有该文件的引用计数,用来计算该文件被多少个进程打开了。如果一个进程将该文件对应的fd关闭则减少对应的引用计数,只有当引用计数为0时文件才会被真正的关闭

完.

相关文章:

【Linux】文件描述符 fd

目录 一、C语言文件操作 1.1 fopen和fclose 1.2 fwrite和fread 1.3 C语言中的输入输出流 二、Linux的文件系统调用 2.1 open和文件描述符 2.2 close 2.3 read 2.4 write 三、Linux内核数据结构与文件描述符 一、C语言文件操作 在C语言中我们想要打开一个文件并对其进…...

带通采样定理

一、采样定理 1.1 低通采样定理(奈奎斯特采样) 低通采样定理&#xff08;奈奎斯特采样&#xff09;是要求大于信号的最高上限频率的两倍 1.2 带通采样定理 带通信号的采样频率在某个时间小于采样频率也能无失真恢复原信号 二、频谱混叠 对一个连续时域信号&#xff0c;采…...

运维工作中的事件、故障排查处理思路

一、运维工作中的事件 https://www.51cto.com/article/687753.html 二、运维故障排查 一&#xff09;故障排查步骤 1、明确故障 故障现象的直接表现故障发生的时间、频率故障发生影响哪些系统故障发生是否有明确的触发条件   故障举例&#xff1a;无法通过ssh登录系统 影响…...

深入源码P3C-PMD:使用流程(1)

PMD开源组件启动流程介绍 在软件开发领域&#xff0c;代码质量是项目成功的关键因素之一。为了提升代码质量&#xff0c;开发者们常常借助各种工具进行代码分析和检查。PMD作为一款开源的静态代码分析工具&#xff0c;在Java、JavaScript、PLSQL等语言项目中得到了广泛应用。本…...

java~反射

反射 使用的前提条件&#xff1a;必须先得到代表的字节码的Class&#xff0c;Class类用于表示.class文件&#xff08;字节码&#xff09; 原理图 加载完类后&#xff0c;在堆中就产生了一个Class类型的对象&#xff08;一个类只有一个Class对象&#xff09;&#xff0c;这个对…...

【Linux】(26) 详解磁盘与文件系统:从物理结构到inode机制

目录 1.认识磁盘、 1.1 理论 1.2 磁盘的物理结构 CHS 寻址 1.3 磁盘的逻辑抽象结构 2. inode 结构 1.Boot Block 启动块 2.Super Block&#xff08;超级块&#xff09; 3.Group Descriptor Block&#xff08;块组描述符&#xff09; 4.Data Blocks (数据块) 5.Inode…...

8.1 字符串中等 43 Multiply Strings 38 Count and Say

43 Multiply Strings【默写】 那个难点我就没想先解决&#xff0c;原本想法是先想其他思路&#xff0c;但也没想出。本来只想chat一下使用longlong数据类型直接stoi()得不得行&#xff0c;然后就看到了答案&#xff0c;直接一个默写的大动作。但这道题确实考察的是还原乘法&…...

upload-labs靶场:1—10通关教程

目录 Pass-01&#xff08;JS 验证&#xff09; Pass-02&#xff08;MIME&#xff09; Pass-03&#xff08;黑名单绕过&#xff09; Pass-04&#xff08;.htaccess 绕过&#xff09; Pass-05&#xff08;大小写绕过&#xff09; Pass-06&#xff08;空格绕过&#xff09; …...

Hive3:一键启动、停止、查看Hive的metastore和hiveserver2两个服务的脚本(好用)

脚本内容 #!/bin/bash # 一键启动、停止、查看Hive的metastore和hiveserver2两个服务的脚本 function start_metastore {# 启动Hive metastore服务hive --service metastore >/dev/null 2>&1 &for i in {1..30}; doif is_metastore_running; thenecho "Hiv…...

遗传算法与深度学习实战——生命模拟及其应用

遗传算法与深度学习实战——生命模拟及其应用 0. 前言1. 康威生命游戏1.1 康威生命游戏的规则1.2 实现康威生命游戏1.3 空间生命和智能体模拟 2. 实现生命模拟3. 生命模拟应用小结系列链接 0. 前言 生命模拟是进化计算的一个特定子集&#xff0c;模拟了自然界中所观察到的自然…...

大数据|使用Apache Spark 删除指定表中的指定分区数据

文章目录 概述方法 1: 使用 Spark SQL 语句方法 2: 使用 DataFrame API方法 3: 使用 Hadoop 文件系统 API方法 4: 使用 Delta Lake使用注意事项常见相关问题及处理结论 概述 Apache Spark 是一个强大的分布式数据处理引擎&#xff0c;支持多种数据处理模式。在处理大型数据集时…...

OSPF动态路由协议实验

首先地址划分 一个骨干网段分成三个&#xff0c;r1&#xff0c;r2&#xff0c;r5三个环回网段 &#xff0c;总共要四个网段 192.168.1.0/24 192.168.1.0/26---骨干网段 192.168.1.0/28 192.168.1.16/28 192.168.1.32/28 备用 192.168.1.64/28 192.168.1.64/26---r1环回 192.1…...

tcp中accept()的理解

源码 参数理解 NAMEaccept, accept4 - accept a connection on a socketSYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);#define _GNU_SOURCE …...

让我们逐行重现 GPT-2:第 1 部分

欢迎来到雲闪世界。Andrej Karpathy 是人工智能 (AI) 领域的顶尖研究人员之一。他是 OpenAI 的创始成员之一&#xff0c;曾领导特斯拉的 AI 部门&#xff0c;目前仍处于 AI 社区的前沿。 在第一部分中&#xff0c;我们重点介绍如何实现 GPT-2 的架构。虽然 GPT-2 于 2018 年由 …...

第十九天内容

上午 1、构建vue发行版本 2、java环境配置 jdk软件包路径&#xff1a; https://download.oracle.com/java/22/latest/jdk-22_linux-x64_bin.tar.gz 下午 1、安装tomcat软件 tomcat软件包路径&#xff1a; https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.26/bin/apache-to…...

Hive之扩展函数(UDF)

Hive之扩展函数(UDF) 1、概念讲解 当所提供的函数无法解决遇到的问题时&#xff0c;我们通常会进行自定义函数&#xff0c;即&#xff1a;扩展函数。Hive的扩展函数可分为三种&#xff1a;UDF,UDTF,UDAF。 UDF&#xff1a;一进一出 UDTF&#xff1a;一进多出 UDAF&#xff1a…...

jdk1.8中HashMap为什么不直接用红黑树

最开始使用链表的时候&#xff0c;空间占用比较少&#xff0c;而且由于链表短&#xff0c;所以查询时间也没有太大的问题。可是当链表越来越长&#xff0c;需要用红黑树的形式来保证查询的效率。 参考资料&#xff1a; https://blog.51cto.com/u_13294304/3075723...

消息推送只会用websocket、轮询?试试SSE,轻松高效。

SSE介绍 HTTP Server-Sent Events (SSE) 是一种基于 HTTP 的服务器推送技术,它允许服务器向客户端推送数据,而无需客户端发起请求。以下是 HTTP SSE 的主要特点: 单向通信: SSE 是一种单向通信协议,服务器可以主动向客户端推送数据,而客户端只能被动接收数据。 持久连接: SS…...

Spring-Retry 框架实战经典重试场景

Spring-Retry框架是Spring自带的功能&#xff0c;具备间隔重试、包含异常、排除异常、控制重试频率等特点&#xff0c;是项目开发中很实用的一种框架。 1、引入依赖 坑点&#xff1a;需要引入AOP&#xff0c;否则会抛异常。 xml <!-- Spring-Retry --> <dependency&…...

人工智能在医疗领域的应用与挑战

随着人工智能技术的不断发展&#xff0c;其在医疗领域的应用也越来越广泛。从辅助诊断到治疗决策&#xff0c;人工智能正在逐步改变着传统的医疗模式。然而&#xff0c;人工智能在医疗领域的应用也面临着诸多挑战&#xff0c;如数据隐私、伦理道德等问题。本文将探讨人工智能在…...

Windows下nmap命令及Zenmap工具的使用方法

一、Nmap简介 nmap是一个网络连接端扫描软件&#xff0c;用来扫描网上电脑开放的网络连接端。确定哪些服务运行在哪些连接端&#xff0c;并且推断计算机运行哪个操作系统&#xff08;这是亦称 fingerprinting&#xff09;。它是网络管理员必用的软件之一&#xff0c;以及用以评…...

深入了解-什么是CUDA编程模型

CUDA&#xff08;Compute Unified Device Architecture&#xff0c;统一计算架构&#xff09;是NVIDIA推出的一种面向GPU的并行计算平台和编程模型。它允许开发者利用NVIDIA的GPU进行通用目的的并行计算&#xff0c;从而加速应用程序的运行速度。CUDA编程模型为开发者提供了强大…...

111111111111111111

11111111111111111111...

环境如何搭建部署Nacos

这里我使用的是Centos7&#xff0c; Nacos 依赖 Java环境来运行。如果您是从代码开始构建并运行Nacos&#xff0c;还需要为此配置 Maven环境&#xff0c;请确保是在以下版本环境中安装使用 ## 1、下载安装JDK wget https://download.oracle.com/java/17/latest/jdk-17_linux-x6…...

什么是 5G?

什么是 5G&#xff1f; 5G 是第五代无线蜂窝技术&#xff0c;与以前的网络相比&#xff0c;它提供了更高的上传和下载速度、更一致的连接以及更高的容量。5G 比目前流行的 4G 网络更快、更可靠&#xff0c;并有可能改变我们使用互联网访问应用程序、社交网络和信息的方式。例如…...

优化冗余代码:提升前端项目开发效率的实用方法

目录 前言代码复用与组件化模块化开发与代码分割工具辅助与自动化结束语 前言 在前端开发中&#xff0c;我们常常会遇到代码冗余的问题&#xff0c;这不仅增加了代码量&#xff0c;还影响了项目的可维护性和开发效率。还有就是有时候会接到紧急业务需求&#xff0c;要求立马完…...

SpringCloud Alibaba 微服务(四):Sentinel

目录 前言 一、什么是Sentinel&#xff1f; Sentinel 的主要特性 Sentinel 的开源生态 二、Sentinel的核心功能 三、Sentinel 的主要优势与特性 1、丰富的流控规则 2、完善的熔断降级机制 3、实时监控和控制台 4、多数据源支持 5、扩展性强 四、Sentinel 与 Hystrix …...

Python 3.12新功能(1)

Python 3.12正式发布已经很久了&#xff0c;我才将主要电脑的Python版本从3.11升级到最新。最近刚好工作没有那么紧张了&#xff0c;就来领略下这个最新版本中的新特性。 改善了错误消息 Python作为一门编程语言&#xff0c;简单易学容易上手&#xff0c;童叟无欺&#xff0c;深…...

c++STL容器中vector的使用,模拟实现及迭代器使用注意事项和迭代器失效问题

目录 前言&#xff1a; 1.vector的介绍及使用 1.2 vector的使用 1.2 1 vector的定义 1.2 2 vector iterator&#xff08;迭代器&#xff09;的使用 1.2.3 vector 空间增长问题 1.2.4 vector 增删查改 1.2.5vector 迭代器失效问题。 2.vector模拟实现 2.1 std::vect…...

Android笔试面试题AI答之Activity常见考点

Activity的常见考点可以总结如下&#xff1a; 生命周期管理&#xff1a;理解Activity在不同情况下&#xff08;如屏幕旋转、配置更改、用户操作等&#xff09;的生命周期变化&#xff0c;包括但不限于onCreate、onStart、onResume、onPause、onStop和onDestroy等回调方法。 启…...

娄底市建设网站/网站seo招聘

以百度文库为例&#xff0c;首先找到我们要插入的参考文献&#xff0c;比如 搜索关键词&#xff0c;然后下需要的论文下面点击引用 得到 点击下面导出链接的EndNote&#xff0c;会下载一个.enw文件 找到此文件并双击打开后即已经导入到EndNote中 如果要在word中使用EndNote&…...

wordpress如何上传图片/石家庄最新疫情

文字加工常用于模具标记、零件装饰、简单文字雕刻等&#xff0c;如图6.1所示。文字加工一般在零件精加工之后进行。由于加工的刀具直径很小&#xff0c;很容易折断。因此文字加工切削量少&#xff0c;需要在转速高达10000~30000r/min的高速机或雕刻机上才能以较短的时间完成。文…...

永久免费网站建设/长沙网站优化排名推广

关注"无线技术联盟"提供有价值的物联网市场信息和最新的技术分析利用Python爬取了蓝牙联盟上近一年BQB认证公司的清单&#xff0c;把爬到的有价值的东西写出来分享给大家。1蓝牙认证产品如果配备了蓝牙功能且要在产品外观上注明蓝牙的标识在国际市场上流通&#xff0…...

wordpress第二张缩略图/新泰网站seo

来源&#xff5c;字母榜作者&#xff5c;龙志腾国民第一大应用微信在最新版本中&#xff0c;围绕着视频号一口气更新了8大功能&#xff0c;其中5大功能都与直播业务息息相关&#xff1a;1、视频号直播主播端上线美颜、滤镜、连麦、镜像等功能&#xff1b;2、直播间上线抽奖工具…...

wordpress+搬瓦工迁移/网络运营推广怎么做

hello&#xff0c;大家好&#xff0c;今天为大家更新一期使用遗传算法(GA)求解旅行商问题(TSP)的推文。本次推文所编写的代码使用如下进化操作&#xff1a;1、二元锦标赛选择操作&#xff1b;2、OX交叉操作&#xff1b;3、交换、逆转和插入相结合的变异操作。一 | 旅行商(TSP)问…...

公司微信网站制作/企业如何开展网络营销

---layout: posttitle: "linux ssd bug"date: 2019-09-30categories: hardware---# 1. bug 描述安装了 manjaro 的 xps 9350&#xff0c;睡眠长时间放电后&#xff0c;无法启动系统。现象&#xff1a;- 电脑可以正常启动 bios, 可以进入 grub, 选择 manjaro 后无法找…...