【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件

目录

​编辑

前言

系统调用

open

参数flags

 参数mode

write

追加方式

read

close

 文件描述符

打开多个文件并观察其文件描述符

C语言文件操作

理解一切皆文件 

理解open操作


前言

各类语言的文件操作其实是对系统调用的封装

我们经常说,创建一个文件,或者打开一个文件,其实并不是我们用户本身创建,而是进程创建文件。文件是存储在磁盘上的,是硬件,像文件写入其实就是向硬件写入,而我们用户这一角色是没有权力直接写入的,操作系统(OS)是硬件的管理者,必须要通过OS写入;

但是,OS不相信任何人,只是提供了系统调用接口对外,想访问文件,就需要使用系统调用;而C/C++..语言都提供了这些系统调用的封装,为何要封装呢?跨平台性。

系统调用

open

打开一个文件,返回一个文件描述符,可以以flags形式打开文件

//2号手册 是系统调用(System Calls)  查找系统调用里面的open函数
man 2 open   

pathname:表示文件的路径名,也可以是一个文件名;如果没有路径名,默认在当前文件下;
flags:表示打开文件的方式选项,参见选项有: 

  • O_WRONLY:只写打开
  • O_CREAT:文件不存在时创建文件
  • O_RDONLY:只读打开
  • O_RDWR:读写方打开
  • O_APPEND:追加方式打开
  • O_TRUNC:清空文件,重新写入

mode:如果这个文件不存在,那么以写的方式打开的时候就会创建这个文件,在创建文件的时候需要给这个文件设定权限(使用八进制数)(会被umask影响);

        如果这个文件存在的话,那么就不用传第三个参数了,因为文件的权限已经确定了

参数flags

open函数定义中,flags是以整形定义的,有32比特位,满足参数个数不固定的情况,以二进制形式传参;

        实际上是一个32位二进制的位图,位图(Bitmap)是一种基于位操作的数据结构,用于表示一组元素的集合信息。位图中的每个二进制位都表示着某个元素是否在集合中。

        比如宏O_WRONLY假设表示的是2即10(二进制),O_CREAT表示4,即100(二进制)。那么O_WDONLY|O_CREAT=110(二进制)。在open函数内部就会有相应的机制监测flags的二进制位哪些是1,再分别对应其代表的功能

 参数mode

表示一个四位八进制的数,取后三位来表示各个角色的权限;

例:0666,取666用二进制表示的就是110 110 110分别对应文件的拥有者、所属组、其他人的(other)权限。

如果当文件不存在时,就要设置该参数,不然就会出现权限处乱码

当新建一个文件时,一定要加上mode参数,来设置权限

 

umask默认为002,也就是过滤掉了“其他人”的w权限,所以得到的最终文件权限编码是664。 

文件权限和权限掩码的关系:文件权限& (~umask权限掩码)

write

用于向文件中写入数据。通过指定文件描述符、数据来源的缓冲区地址和要写入的字节数;可以将数据写入到文件中。如果写入失败则返回-1,否则返回写入的字节数;

  • fd表示的是文件标识符
  • buf表示的是数据的地址;
    • 对于系统调用来说,它并不在意写入的数据是什么类型的,它接收到的数据都是二进制的数字,然后按照字节为单位写入。
  • count表示的是字节数
  • 返回值类型: ssize_t 类型表示有符号整型,输出格式为%ud.

 

追加方式

以追加方式写入,只需要在open(...)第二个参数中 把O_TRUNC换成O_APPEND

read

用于从文件中读取数据。通过指定文件描述符、缓冲区地址和读取的字节数;

可以将文件中的数据读取到缓冲区中。

读取成功返回读取的字节数,否则返回-1.

int fd:打开文件时返回的文件描述符。
void* buf:从文件中读取的数据放在这个数组中,同样系统不管文件中的数据类型是什么,都是按字节放入这个数组中。
size_t count:要读取的字节个数。
ssize_t:读取了多少个返回多少。 

使用只读方式打开(目标文件已经存在,open(...)中mode参数可以不用加入设置);

将读取的内容放在ch_arr数组中。 

close

用于关闭一个文件描述符,释放系统资源。(也就是令struct file* fd_array[]对应下标fd指向空。)

在文件操作完成后,应该及时关闭文件描述符,以防资源泄漏。

关闭成功返回0,否则返回-1.

 文件描述符

 操作系统要管理文件,必定要让文件先加载到内存,然后先描述,再组织。内核中要有描述对应文件的结构体——也就是struct file

        struct file中最核心的数据可以分为3大类,属性,方法集,缓冲区。而文件描述符fd就存在属性当中。

        文件是由进程发起创建的,而一个进程实际上是一个PCB(task_struct),里面有一个结构体指针struct file_struct* files,指向了一个结构体。这个结构体中又有一个指针数组struct file* fd_array[N]该指针数组存放了指向进程所打开文件的结构体下标,也就是文件描述符fd;

  • 内核会返回一个小的非负整数。这个非负整数就叫做描述符,也叫文件描述符。文件描述符是用于唯一标识文件的号码。
  • 进程实际上并不记录文件本身,而只需要记录一个为一个文件ID。所有被打开的文件的信息都被集中在一起被内核管理,内核向进程提供文件的接口。

打开多个文件并观察其文件描述符

创建的每一个进程开始的时候都有三个打开的文件:标准输入流(fd=0),标准输出流(fd=1),标准错误流(fd=2)。

 这三个文件分别对应的硬件设备是键盘、显示器、显示器。

而这三个都是默认自动打开的

 

当进程打开文件时,会在struct file*数组中找到当前没有被使用的最小的下标,作为新的文件标识符。

如果在打开文件之前,把这个三个文件流关闭,那么就会自动分配到当前的最小下标。

C语言文件操作

C语言文件操作默认打开三个输入输出流,分别是stdin,stdout,stderr。 

 之前提到过,不同语言的文件操作不过是对系统调用的封装,这里发现C语言的返回值和系统调用open..返回值不一样,我们大胆猜测FILE是一种封装

 打印输入输出流

 

 可以发现,FILE结构体中是有文件描述符的。

文件描述符fd的分别规则是:从小到大,按顺序查找,将没有被占用的数组下标作为被打开文件的文件描述符fd值。

理解一切皆文件 

这个文件可以理解成结构体

  • 每一个硬件,操作系统都会维护一个struct file类型的结构体,硬件的各种信息都在这个结构体中,并且还有对应读写函数指针(对硬件的操作主要就是读写)。
  • 每个硬件的具体读写函数的实现方式都在驱动层中,使用到相应的硬件时,操作系统会通过维护的结构体中的函数指针调用相应的读写函数。

 

  •  站在操作系统的角度来看下层,无论驱动层和硬件层中有什么,在它看来都是struct file结构体,都是通过维护这个结构体来控制各种硬件。
  • 站在操作系统的角度来看上层,无论用户层以及系统调用有什么,在它看来都是一个个进程,都是一个个的task_struct结构体,都是通过维护这个结构体来调度各个进程的。
  • 真正的文件在操作系统中的体现也是结构体,操作系统维护的同样是被打开文件的结构体而不是文件本身。

理解open操作

  • 创建struct file(包括fd)
  • 开辟文件缓存区,加载文件中的数据(延后)
  • 查进程的文件描述符表(fd_array数组)
  • 将file的内存地址填入到fd_array[fd]中
  • 返回fd. 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣第三十七题——解数独

内容介绍 编写一个程序,通过填充空格来解决数独问题。 数独的解法需 遵循如下规则: 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) 数独…

每天一个数据分析题(四百四十四)- 数据仓库

企业数据仓库里面的数据一般是由业务数据经过ETL技术处理后来的,以下关于ETL的说法错误的是 A. ETL过程中的主要环节是数据抽取、数据转换和加工、数据流转 B. 增量数据抽取过程中,提取增量数据的方法有通过时间戳、建立触发器、全表比对、日志比对等 …

springboot整合pgsql

demo代码说明 springboot使用mybatis-plus整合pgsql 在springboot项目中使用pgsql,使用了mybatis-plus、druid 代码见 spring-demo: springboot 结合各种插件 demo 注意事项: 版本兼容 正常springboot使用,但是注意需要添加pgsql正确版…

CVE-2024-39700 (CVSS 9.9):JupyterLab 模板中存在严重漏洞

在广泛使用的 JupyterLab 扩展模板中发现了一个严重漏洞,编号为CVE-2024-39700 。此漏洞可能使攻击者能够在受影响的系统上远程执行代码,从而可能导致大范围入侵和数据泄露。 该漏洞源于在扩展创建过程中选择“测试”选项时自动生成“update-integratio…

VIM基础配置

1. CTAGS配置 下载 上传虚拟机,解压,进入目录 tar -xzvf ctags-5.8.tar.gz cd ctags-5.8/编译 ./configure sudo make sudo make install查看是否安装成功 ctags --version打印如下 2. 使用Vundle 下载 git clone https://github.com/VundleVim/Vund…

Linux并发程序设计(3):守护进程

目录 前言 一、介绍 1.1 概念 1.2 特点 1.3 举例 二、系统编程 2.1 setsid函数 2.2 getpid函数 2.3 getsid函数 2.4 getpgid函数 2.5 chdir函数 三、代码例程 3.1 使子进程在后台运行 3.2 使子进程脱离原终端 3.3 更换目录,并设定权限(非…

React--Redux

Redux 是一个用于 JavaScript 应用的状态管理库,特别是在 React 应用中非常流行。下面我将详细介绍一个使用 Redux 的简单案例,包括设置 Redux 环境、创建 store、定义 actions 和 reducers,以及如何连接 React 组件。 步骤 1: 安装依赖 首…

基于STM32通过云平台实现智慧大棚【手机远程查看温湿度】【报警】

文章目录 一、成果演示二、所用到的模块三、实现的功能四、接线说明五、WIFI模块配置步骤5.1云平台介绍5.2云平台使用5.3使用USB转TTL测试联通云平台 六、STM32代码编写七、手机上查看数据6.1下载软件(仅限安卓手机)6.2操作 一、成果演示 STM32通过物联网…

String、StringBuffer和StringBuilder

一、String类 1. String类的理解 2. String类结构 1. String类实现了Serializable接口,说明String对象可以串行化,即可以在网络上传输 2. String类实现了Comparable接口,说明String对象可以比较 String底层是一个字符数组,这个数组里存的是字符串的内容 例如:…

005 仿muduo实现高性能服务器组件_通信连接管理

​🌈个人主页:Fan_558 🔥 系列专栏:仿muduo 📒代码仓库: 项目代码 🌹关注我💪🏻带你学更多知识 文章目录 前言Channel模块设计原因整体设计代码如下 Connection模块设计原…

Florence2:Advancing a unified representation for a variety of vision tasks

Florence-2模型:开启统一视觉基础模型的新篇章_florence -2-CSDN博客文章浏览阅读1.1k次,点赞108次,收藏109次。Florence-2是由微软Azure AI团队开发的一款多功能、统一的视觉模型。它通过统一的提示处理不同的视觉任务,表现出色且优于许多大型模型。Florence-2的设计理念是…

用Postman Flows打造你的专属API:外部公开,轻松上手!

引言 Postman Flows 是一个使用 GUI 进行无代码 API 调用流程创建的服务。这篇文章我尝试使用 Flows 来构建将 Momento Topic 中的数据保存到 TiDB 的保存 API,因此想分享一些使用过程中的技巧等。 实现内容 将从 Momento Topics 配发的 JSON 数据保存到 TiDB 中。…

3086. 拾起 K 个 1 需要的最少行动次数

3086. 拾起 K 个 1 需要的最少行动次数 题目链接:3086. 拾起 K 个 1 需要的最少行动次数 代码如下: //参考链接:https://leetcode.cn/problems/minimum-moves-to-pick-k-ones/solutions/2692009/zhong-wei-shu-tan-xin-by-endlesscheng-h972 class Sol…

CrowdStrike引发全球微软系统大宕机:事故解析及网络安全反思

引言 近日,一次由CrowdStrike推送的更新引发了全球IT系统大规模故障。超过850万台电脑受到影响,涵盖各个行业和领域,引发了广泛关注和讨论。本文将详细解析此次事件的来龙去脉,评估其影响,并探讨网络安全的现状及未来…

C++ 栈( stack )学习

目录 1.栈 2.模拟栈 1.1.入栈( push ) 1.2.出栈( pop ) 1.3.获取栈顶元素( top ) 3.直接使用栈( stack ) 3.1.导入头文件并创建栈 3.2.栈的操作 3.2.1.入栈( push ) 3.2.2.出栈( pop ) 3.2.3.获取栈顶元素( top ) 3.2.4.获取栈中元素个数( size ) 3.2.5.判断栈是否…

代码随想录算法训练营day8 | 344.反转字符串、541.反转字符串 II、卡码网:54.替换数字

文章目录 344.反转字符串思路 541.反转字符串 II思路 卡码网:54.替换数字思路复习:字符串 vs 数组 总结 今天是字符串专题的第一天,主要是一些基础的题目 344.反转字符串 建议: 本题是字符串基础题目,就是考察 revers…

ChatGPT:宽列数据库是什么?

ChatGPT:宽列数据库是什么? 宽列数据库(Wide-Column Store)是一种 NoSQL 数据库,它的设计灵感来自于 Google 的 Bigtable。宽列数据库适用于处理大规模的分布式数据存储,特别是在需要高性能读写、灵活的数据…

docker挂载部署reids6.2.1

1.拉取镜像 docker pull redis:6.2.12.创建挂在目录(根据自己要求修改具体目录) mkdir -p /home/admin/redis/{data,conf}3.在/home/admin/redis/conf目录下创建redis.conf文件 cd /home/admin/redis/conf touch redis.conf4.复制下面文本到redis.conf…

深入理解 Laravel 中的会话管理

引言 会话管理是 Web 应用中一个至关重要的功能,它允许应用识别并跟踪用户的会话状态。Laravel 提供了一个强大而灵活的会话管理系统,使得开发者可以轻松实现用户状态的跟踪和管理。本文将详细介绍 Laravel 中的会话管理机制,包括会话的创建…

浅析JWT原理及牛客出现过的相关面试题

原文链接:https://kixuan.github.io/posts/f568/ 对jwt总是一知半解,而且项目打算写个关于JWT登录的点,所以总结关于JWT的知识及网上面试考察过的点 参考资料: Cookie、Session、Token、JWT_通俗地讲就是验证当前用户的身份,证明-…