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

Linux文件fd剖析

学习之前,首先要认识什么是文件?

  1. 空文件也是要在内存中占据空间的,因为它还有属性数据。
  2. 文件 = 属性 + 内容
  3. 文件操作 = 对内容 + 对属性 或者对内容和属性的操作
  4. 标定一个文件的时候,必须使用:路径+文件名,文件具有唯一性
  5. 如果没有指明文件路径,默认是对当前路径的文件进行访问
  6. 文件没有被打开的时候是不能进行访问的
  7. 二进制可执行文件在没有运行的时候,所谓的文件操作都没有执行
  8. 磁盘上文件被分为被打开的文件和没有被打开的文件

总结:文件操作的本质,是进程和被打开文件之间的关系。

一、文件操作

1.1 使用C接口进行文件操作(用C语言头文件和C语言在Liunx下的表达形式)

在将我们的程序编译完成以后,再运行,发现生成了一个新的文件,并且文件中的内容和我们代码中写的一样。

  • 这个过程中,使用的是C语言的接口进行文件操作。
  • 以写的方式打开文件名问log.txt的文件,没有的这个文件的话就会创建。
  • 使用C接口向该文件中写入内容。

不同的编程语言都有文件操作的接口,包括C++,Java,Python,php等等语言,并且它们的操作接口函数都不一样,但是它们所在的系统都是Linux系统。

无论上层语言如何变化,但是进行文件操作的时候,各种语言最终都会调用Linux的文件操作的系统调用接口。

1.2 文件操作的系统调用

open函数:

可以看到,函数声明有两个,一个是两个参数的,一个是三个参数的,它们必然不是函数重载,因为Linux是用纯C实现的。

  • const char* pathname:这是文件路径,也就是我们要打开的文件所在的路径,其中包括文件名,如果没有路径只有文件名的话,默认在当前路径打开。
  • int flags:打开方式选项标志位。在使用C语言进行文件操作的时候,打开方式有“w”,“r”,“a”等方式,系统调用open也有,只是将这些标志放在了一个32位的变量中。
  • mode_t mode:它是权限值,如果这个文件不存在,那么以写的方式打开的时候就会创建这个文件,在创建文件的时候需要给这个文件设定权限(使用八进制数)。如果这个文件存在的话,那么就不用传第三个参数了,因为文件的权限已经确定了。
  • 返回值:是一个int类型的参数,具体的在后面本喵会介绍,但是如果打开失败就会返回-1。

执行我们写的代码后,log.txt文件是创建了,但是它是红色的,说明它有错误。可以看到它前面的权限是乱的,因为我们没有指定创建文件时的权限。

但是权限并不是我们设定的0666,而是0664,这是因为有默认权限掩码(umask)的影响。

此外还有close函数,write函数,使用 man + 函数名指令查看相应参数

二、文件描述符fd

在使用系统调用open时,返回的那个整数就是文件描述符。

将文件名使用宏的方式打开多个文件。

现在我们见到了文件描述符,发现它就是几个数字。

当一个文件被打开后,操作系统会创建一个对应的结构体对象,类型是struct file。

struct file
{//文件大小//文件类型......//文件的各种属性
}
  • 每打开一个文件,操作系统就会创建这样的一个结构体对象将被打开的文件描述出来。
  • 将多个这样的结构体对象采用一定的方式组织起来,比如链表的方式,以方便操作系统管理这些被打开的文件。

在描述进程的结构体task_struct中,有一个指针,struct files_struct* files,这个指针指向一个结构体对象,该对象类型如下:

struct files_struct
{//......struct file* array[];
}
  • struct files_struct结构体中存在一个指针数组array,该数组中的指针指向的是一个个struct file类型的结构体对象。
  • 换言之,该数组中放的是被打开文件结构体对象的地址。
  • 每一个被指向的struct file结构体对象都描述着一个被打开的文件。

在前面我们看到,打印出来的fd值是连续的小整数,这些小整数就是struct files_struct 结构体中指针数组struct file* array[]的下标。

文件描述符的本质,就是数组的下标。

  • 当一个程序被加载到内存中,操作系统会创建一个结构体struct task_struct对象,在该结构体中有一个指针struct files_struct* files,指向一个struct files_struct结构体对象。
  • 这个结构体也被叫做进程描述符表,该结构体中有一个数组struct file* array[],数组中存放的是被打开文件的结构体对象的地址。如上图中,下标为3,也就是fd的是3的时候,访问到的是struct file* array[3]。
  • 通过数组中访问到的地址,可以找到对应打开文件的结构体对象,如上图中的struct file log.txt。

只有被打开的文件才会在内存中创建struct file结构体对象,没有被打开的文件就静静的躺在磁盘上。

不是该进程打开的文件,该进程执行的文件描述符表中也没有这个文件的地址。

2.1 文件描述符fd=0/1/2

在上面打开多个文件的时候,我们将打开文件的fd值打印出来,发现它是从3开始的。

那么fd = 0/1/2是什么呢?

C默认会打开三个输入输出流,分别是stdin,stdout,stderr。

可以看到,这三个流是FILE*类型的指针,暂时不用管FILE是什么,只需要知道它是一个结构体。

使用C语言的文件操作结构打开一个文件,再使用系统调用去向文件中写内容。

我们此时已经确定的知道了,FILE结构体中是有文件描述符的。

文件描述符0 1 2出现了。

  • fd = 0:标准输入流(stdin)
  • fd = 1:标准输出流(stdout)
  • fd = 2:标准错误(stderr)

此时我们便清楚了为什么我们打开的文件,文件描述符是从3开始的,因为012被默认打开的三个流占据了。

2.2 文件描述符的分配规则

为什么我们打开的文件,fd是从3开始的?不是从5或者6开始的呢?

我们将fd=0的标准输入流关闭掉,再打开文件,并且打印fd值。

我们发现此时的fd成了0,而不是3了。

同样的,将fd=2的流关闭,在打开文件。

根据这个现象,可以得出结论:文件描述符fd的分别规则是:从小到大,按顺序查找,将没有被占用的数组下标作为被打开文件的文件描述符fd值。

三、重定向

3.1 输出重定向

前面我们只关闭过0和2,没有关闭过1,现在我们关闭一下1来看看。

将标准输出关闭,然后打开文件,并且打印出打开文件的文件描述符fd。

  • 因为将标准输出关闭了,所以无法显示。

根据前面分析的文件描述符分配规则,可以推断出,将标准输出关闭以后,再打开一个文件,此时这个文件的文件描述符fd等于1。

  • 在将fd=1关闭后,再打开一个文件,从小到大按顺序查找,发现数组下标为1的位置没有被占用,所以新打开文件的fd就等于1。
  • printf函数原本是要输出到标准输出的,也就是fd为1的数组中指向的struct file对象的地址。
  • 此时下标为1的数组中不再是标准输出了,而变成了我们新打开文件的地址。
  • 但是printf已经写死了,它仍然会写入到fd为1的文件中,所以原本打印在显示器上的内容此时会写入到新打开的文件中。

3.2 输入重定向

使用只读方式打开文件log.txt该文件原本就存在。

  • 将原本struct file* array[]数组中下标0的内容改成下标为fd的内容,也就是dup2(fd,0)的作用。
  • 使用标准输入函数fgets,从标准输入流也就是键盘中读取字符串。
  • 屏幕上打印读取到的内容。

运行时直接输出log.txt中的内容,没有从键盘获取数据。也就是说,fgets函数是从文件中获取到内容,而不是标准输入。

这种从标准输入到文件的重定向叫做输入重定向。

3.3 进程独立性

子进程重定向了以后,会影响父进程吗?根据进程独立性我们可以知道,肯定是不会影响到。

在子进程中进行输出重定向,父进程同样在标准输出打印。

  • 有两个进程,一个父进程,一个子进程,操作系统维护着两个task_struct结构体,如上图红色框所示。
  • 每个进程的PCB中都有一个struct files_struct*的指针files。它们各自指向的struct files_struct结构体中都有一个文件描述符表。
  • 两个文件描述符表中的内容在子进程刚创建时是一样的,所以它们都指向相同的被打开的文件。
  • 当子进程将自己文件描述符表中下标为1的文件关闭以后,并不影响父进程文件描述符表中下标为1的数组中的内容。

每个进程都会维护自己的文件描述符表,所以多个进程就会存在多个文件描述符表,但是这些表中的指针指向的被打开文件只有一套。

某个进程进行文件的打开与关闭操作时,只需要修改自己的文件描述符表就可以,不会对其他进程造成任何影响。

一切皆文件是指:在操作系统中一切都是结构体。

相关文章:

Linux文件fd剖析

学习之前,首先要认识什么是文件? 空文件也是要在内存中占据空间的,因为它还有属性数据。文件 属性 内容文件操作 对内容 对属性 或者对内容和属性的操作标定一个文件的时候,必须使用:路径文件名,文件具…...

VMWARE ESXi存储多路径策略修改

一、存储多路径介绍 VMware 路径选择插件 (PSP) 负责选择 I/O 请求的物理路径。插件是 VMware NMP 的子模块。NMP 根据设备类型为每个逻辑设备分配默认 PSP。每个PSP 启用并执行相应的路径选择策略。支持的路径选项有以下3种: VMW_PSP_MRU - 最近使用 它将选择在系…...

结构体详解

结构体: 一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构 结构体可以用来封装一些属性来组成新的类型。 结构体的大小: 结构体的大小不是结构体元素单纯相加。内存对齐(若计算机使用32位字长的cpu,对32位的…...

前端开发个人简历范本(2024最新版-附模板)

前端开发工程师个人简历范本> 年龄 25岁 性别 男 毕业院校 XX大学 张三 学历 邮箱 leeywai-tools.cn 本科 专业 计算机科学与技术 个人梗概 拥有扎实的前端开发技能和丰富的实践经验 善于与团队合作,适应能力强,能够快速融入团队并贡献自…...

# 编程语言简史

编程语言简史 文章目录 编程语言简史1. python简史1. python发展历程 2. python适用领域1. 优点:2. 缺点:3. 应用领域: 2. java简史1. java发展历程2. java适用领域 3. C简史1. C发展历程2. C使用领域 4. C简史1. C发展历程2. C适用领域 5. C…...

SpringMVC学习与开发(三)

注:此为笔者学习狂神说SpringMVC的笔记,其中包含个人的笔记和理解,仅做学习笔记之用,更多详细资讯请出门左拐B站:狂神说!!! 10、ssm整合 问了一下ChatGPT SSM 是一个基于 Java 的开发框架整合,由 Spring、…...

JAVA对象、List、Map和JSON之间的相互转换

JAVA对象、List、Map和JSON之间的相互转换 1.Java中对象和json互转2.Java中list和json互转3.Java中map和json互转 1.Java中对象和json互转 Object obj new Object(); String objJson JSONObject.toJSONString(obj);//java对象转json Object newObj JSONObject.parseObject(…...

图像分割-漫水填充法 floodFill

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 本文的C#版本请访问:图像分割-漫水填充法 floodFill (C#)-CSDN博客 FloodFill方法是一种图像处理算法&#…...

Python open函数详解:打开指定文件与 readline和readlines函数:按行读取文件

Python open函数详解:打开指定文件 掌握了各种操作目录字符串或目录的函数之后,接下来可以准备读写文件了。在进行文件读写之前,首先要打开文件。 Python 提供了一个内置的 open() 函数,该函数用于打开指定文件。 open() 函数的…...

Vue 生命周期有哪些?作用是什么?

什么是vue的生命周期 Vue 实例从开始创建、初始化数据、编译模板、挂载Dom和渲染、更新和渲染、卸载等一系列过程,这是 Vue 的生命周期 vue的生命周期的八个钩子函数 beforeCreat() 创建前 在new一个vue实例后,只有一些默认的生命周期钩子和默认事件&a…...

《Vue3 前端构建工具》 Vue-cli 与 Vite 创建项目的插件和配置对比

前言 2024 年 啦!Vue2 也于 2023.12.31 寿终正寝 ! 然而我的 Vue3 升级一再拖延(惭愧不已)~ 赶起来吧~ 今天用 vue-cli 和 vite 分别创建了 Vue3 项目,具体实现步骤见如下两篇。 《基于 Vue Cli4.x Vue3 TS styl…...

springboot(ssm中山社区医疗综合服务平台 医疗管理系统 Java系统

springboot(ssm中山社区医疗综合服务平台 医疗管理系统 Java系统 开发语言:Java 框架:ssm/springboot vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7(或8.0&#x…...

Qt编写的exe程序上添加程序信息

1、qtcreator编写 在pro文件中添加如下信息 # 版本信息 VERSION 4.0.2.666# 图标 RC_ICONS Images/MyApp.ico# 公司名称 QMAKE_TARGET_COMPANY "Digia"# 产品名称 QMAKE_TARGET_PRODUCT "Qt Creator"# 文件说明 QMAKE_TARGET_DESCRIPTION "Qt …...

(一)CarPlay集成开发之概述与环境篇

系列文章目录 第一章 CarPlay集成开发之概述与环境篇 文章目录 系列文章目录概述开发环境依赖项总结 概述 CarPlay是由苹果公司开发的一款集成在iOS系统中,用于运行在已完成对接该系统的汽车中控台,仪表盘上的车载系统,该系统通过USB或者WI…...

js文件上传 分片上传/断点续传/极速秒传

(极速秒传)利用md5判断上传的文件是否存在 MD5信息摘要算法,一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。 每一个文件都会生成…...

mysql 通过 binglog 恢复数据

mysql 通过 binglog 恢复数据 测试数据库版本: 8.0.5 查看当前是否开启 进入数据库,查看当前是否开启了 binglog 的相关设置: mysql> show variables like log_bin%; -------------------------------------------------------------- | Variable_name …...

【REST2SQL】01RDB关系型数据库REST初设计

0 概念 REST2SQL实现连接数据库,数据库的表或视图即可提供REST的GET\POST\PUT\DELETE请求,SQL可执行SQLECT\INSERT\UPDATE\DELETE语句。 0.1 RDB Relational Database 即关系型数据库(简称 RDB)是一种以关系(即表格…...

图像识别原理

图像识别是计算机视觉领域中的一个重要任务,其目标是使计算机系统能够理解和解释图像中的信息。以下是图像识别的基本原理: 1. 数据采集:首先,需要获取图像数据。这可以通过摄像头、传感器、扫描仪等设备来实现。图像可以是静态的…...

共识算法介绍

文章目录 共识算法Paxos 算法三种角色一致性提交算法prepare 阶段accept 阶段commit 阶段 CAP 定理BASE 理论Zookeeper 算法实现三类角色三个数据三种模式四种状态消息广播算法Leader选举算法 共识算法 Paxos 算法 Paxos 算法是莱斯利兰伯特(Leslie Lamport)1990 年提出的一种…...

Gen-AI 的知识图和分析(无需图数据库)

如今,图表比以往任何时候都更加相关和有用。由于目前正在发生的人工智能革命,工程师们正在考虑围绕 Gen-AI 的机会,利用具有动态提示、数据基础和屏蔽功能的开放 Gen-AI 解决方案,这进一步促使他们思考知识图谱等有效的解决方案。…...

flutter 安卓使用高德插件黑屏

地址 https://lbs.amap.com/api/android-sdk/guide/create-project/android-studio-create-project 下面介绍的方式是Native配置 sdk,也就是需要手动下载到本地在引入的方式 1、添加 jar 文件: 将下载的地图 SDK 的 jar包复制到工程(此处截…...

Java:表单生成excel文档 poi 通用

在用java 写数据库应用的时候, 通常会生成各种报表,而这些报表可能会被导出为各种格式的文件,比如Excel文档,pdf 文档等等. 今天先做了一个生成Excel 文档的例子,主要解决以下问题: 1. 生成 Excel 文档. 2. 自动对生成…...

使用Apache Commons SCXML实现状态机管理

第1章:引言 大家好,我是小黑,咱们程序员在开发过程中,经常会遇到需要管理不同状态和状态之间转换的场景。比如,一个在线购物的订单,它可能有“新建订单”、“已支付”、“配送中”、“已完成”等状态。在这…...

大数据技术原理与应用期末考试题

大数据技术原理与应用期末考试题 一、单选题 1.下面哪个选项属于大数据技术的“数据存储和管理”技术层面的功能? A、利用分布式文件系统、数据仓库、关系数据库等实现对结构化、半结构化和非结构化海量数据的存储和管理 B、利用分布式并行编程模型和计算框架,结合机器学习…...

解决jenkins的Exec command命令不生效,或者执行停不下来的问题

Jenkins构建完后将war包通过 Publish Over SSH 的插件发布到服务器上,在服务器上执行脚本时,脚本中的 nohup 命令无法执行,并不生效,我配置的Exec command命令是后台启动一个war包,并输出日志文件。 nohup java -jar /…...

【PHP】json_decode的第二个参数是什么意思

json_decode() 函数的第二个参数 $associative 是一个布尔值,用于控制 JSON 对象在 PHP 中的解码方式。当将其设置为 true 时,JSON 对象将被解码为关联数组;当设置为 false 时,JSON 对象将被解码为 stdClass 对象。默认值为 false…...

学生公寓安全用电管理系统应用案例

摘要:安全用电是学校公寓用电管理的首要任务,这就需要对一些恶性负载进行识别和控制,同时为了减少电工和后期管理人员的成本,引进了安全用电管理系统。本文在在描述了安全用电管理系统的工作原理和利用智能电表可实现的功能后,阐明…...

python实现简易的flask后端接口

先安装插件pip install flask 新建py脚本文件编码: # -*- coding: utf-8 -*- from flask import Flask from flask_cors import CORS # 跨域依赖,通过pip install flask-cors安装app Flask(__name__) cors CORS(app) # 跨域设置,这样设置…...

CSDN质量分批量查询

单个文章质量分查询地址(点击右边地址): CSDN质量分查询 创作者身份认证审核标准 优质创作者申请条件: 粉丝数在5000以上近30日(申请日算起)原创文章数不少于4篇原创博文总数不少于100篇垂直领域原创数量…...

【MPC学习笔记】01:MPC简介(Lecture 1_1 Unconstrained MPC)

本笔记来自北航诸兵老师的课程 课程地址:模型预测控制(2022春)lecture 1-1 Unconstrained MPC 文章目录 0 MPC 简介0.1 案例引入0.2 系统模型0.3 MPC的优点0.4 MPC的缺点0.5 MPC的未来 1 详细介绍 0 MPC 简介 0.1 案例引入 MPC(…...

海城网站制作建设/哈尔滨最新消息

一、Amoeba的简述:[来自百度百科] Amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy。它集中地响应应用的请求,依据用户事先设置的规则,将SQL请求发送到特定的数据库上执行。基于此可以实现负载均衡、读写分离…...

4核8g云服务器/专业排名优化工具

仅作为操作记录,大佬请跳过。 plt.subplot(2,2,1);plt.plot(sig) plt.subplot(2,2,2);plt.plot(sigrand) plt.subplot(2,1,2);plt.plot(sigrandsig)传送门...

新闻网站建设的任务要求/网络营销推广方案3篇

左移运算符就是在二进制的基础上对数字进行平移。按照平移的方向和填充数字的规则分为三种&#xff1a;<<(左移)、>>(带符号右移)和>>>(无符号右移)。 在 移位运算时&#xff0c;byte、 short和char类型移位后的结果会变成int类型&#xff0c;对于byte、s…...

美食网站建设策划书/企业网站排名优化方案

2018年谷歌推出了跨平台框架Flutter&#xff0c;一时间让各位技术开发者兴趣暴涨(因为做过混合开发的程序猿早就被js的性能低效&#xff0c;rn的js桥接麻烦&#xff0c;weex的社区小和坑多。。。等技术而感到焦头烂额)。随着高性能的跨平台框架Flutter正式版一发布&#xff0c;…...

深圳市建设厅官方网站/在百度如何发布作品

满意答案wpsfty2016.02.07采纳率&#xff1a;46% 等级&#xff1a;9已帮助&#xff1a;1213人图老师手工制作生活百科美食菜谱设计创意美妆造型电脑网络美容美体综合其它疾病百科育儿百科电脑网络电脑显示不支持此连接口怎么办电脑显示不支持此连接口怎么办标签&#xff1a;…...

国贸做网站公司/如何制作网站

今天&#xff0c;说一Ipad充不了电&#xff0c;我想才没买好久&#xff0c;这么快电池就坏了呀。难道买到歪货了&#xff1f; 它的表现是充电线一接上去&#xff0c;电池指示有反应&#xff0c;也有"闪电"标志&#xff0c;就是充不进去电。本来想打客服的&#xff0c…...