【Linux】进程与文件系统(上)

news2024/11/14 17:31:42

由于这部分的知识很多很多,分成两回 

目录

1.文件描述符 

文件描述符


1.文件描述符 

首先我们看一下几个小问题

1.你真的理解文件原理和操作了吗?

这不是语言的问题,而是操作系统的问题

2.是不是只有C/C++有文件操作?

其他语言python,Java,go...也有文件操作,但是他们的文件操作方法不一样

那如何理解这个现象?有没有统一的角度看待所有语言的文件操作?

理解要学完本文,当然是有统一角度——操作系统角度(看完本文,你自然理解这个问题)

3.操作文件的时候第一件事情都是打开文件,打开文件是在做什么?如何理解?

本文的重点内容

4.文件=内容+属性,针对文件的操作时对内容的操作还是对属性的操作?

对内容+属性的操作

5.文件没被操作时,文件一般在什么位置?磁盘

6.当我们操作文件时,文件需要在哪里?

内存(为什么?因为冯诺依曼体系告诉我们的)

7.当我们对文件操作,文件需要被提前加载到内存,被加载的到底是内容还是属性?

至少要有属性

8.是不是只有你一个人在load?

不是,内存中一定有大量不同的文件属性

9.打开文件的本质:

将需要的文件属性加载到内存,OS内部一定会同时存在大量被打开的文件,那么操作系统要不要管理这些被打开的 文件?

当然,先构建在内存中的文件结构体 struct XXX{} 被打开的文件属性被load到文件结构体中

a.每一个被打开的文件都需要在OS内部对应的文件对象的struct结构体,可以将所有的结构体(其实这种结构体叫struct file)用某种数据结构连接起来,在OS内部,对被打开的文件进行管理 就 转换成对链表的增删查改

上面一段话简而言之:

被打开的文件,OS要为其创建对应的内核数据结构——struct file

struct file

{

//文件的各种属性

//各个file结构体之间的链接关系

}

10.文件其实可以分成两类:磁盘文件,被打开的文件(内存文件)

11.文件被打开,是谁在打开?

OS

是谁让OS打开?用户(进程为代表的)

12.我们之前所有的文件操作都是进程和被打开文件的关系

也就是struct task_struct 和struct file的关系


复习一下C语言的文件操作:

  • 打开文件的方式

w:默认写方式打开,文件不存在则新建,如果只打开文件内容自动被清空,每次写入都会从最开始写

a:不会清空文件,而是每次从文件尾追加(也就是append)

  • 复习几个C库函数

查三号手册 得

 参数列表里面的...是可变参数列表,即参数酌情写

printf //默认向显示器打印

fprintf //

sprintf //向字符串打印

snprintf //和sprintf函数不同的是,他会限制写入str字符串的字符数量为size

 1 #include <stdio.h>
  2 
  3 #define LOG "log.txt"
  4 int main()
  5 {
  6   const char * msg="hello wrt";
  7   printf("%s\n",msg);
  8   FILE * fp=fopen(LOG,"w");
  9   fprintf(fp,"%s",msg);
 10   char buf1[124]={0};
 11   sprintf(buf1,"%s",msg);
 12   printf("%s\n",buf1);                                                                                                
 13   char buf2[124];
 14   snprintf(buf2,4,"%s",msg);
 15   printf("%s\n",buf2);
 16   return 0;
 17 }

结果是 

很奇怪最后这怎么就三个字符输出

并且最后一次我们以为写入4个字符,但是只有 size - 1 个字符被写入缓冲区,最后一个字符为字符串结尾的空字符 \0


  • fgets() 

fegts函数把文件流内容写入到字符串s

 

这个函数遇到EOF(文件末)或者\n , 或者读到size-1个字符就停止读取

会自动在size个字符处填上\0

如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。

如果发生错误,返回一个空指针

  • fputs()

 

 把字符串s写入到文件流

该函数返回一个非负值,如果发生错误则返回 EOF(也就是0)

  • fread 

 


刚才我们在语言方面简单看了一下对文件的一些基本操作函数,现在看几个操作系统层面的系统调用

  • open

 

该函数的返回值是被打开文件的文件描述符

浅浅看一下flags是什么

 

手册里还有更多,真的是头都大了

其实这些大写的flags都是宏,他是OS让用户给自己传递的标志位

表面上他看起来是整数,有32位bit,我们可以用一个bit表示一个标志位,所以一个int最多可以传递32个标志位

简单看一下这个原理

我定义了三个宏,他们在十六进制下二进制位刚好是错开的

重点体会这种位图可以传递信息的思想 

 

 所以,flags的参数是一堆宏,他的二进制位不重叠,一次可以传多个宏

但是发现用open打开的log.txt权限是乱码(根本没有s权限)

 因为用open带上写选项(写的flags)之后,需要对写完之后的文件权限修改

也就是

之前学习过八进制语法:

进制语法. chmod命令可以使用八进制数来指定权限 

这里的mode_t就是输入对应的八进制数即可更改文件的权限

 

这里0表示接下来的数值是八进制表示

rwx:4+2+1=7

666表示文件的权限都设置成rw- 

 

但是此时的文件权限还是原来的样子

是因为umask掩码,那么怎么可以在我自己的进程短暂改变掩码?

 

 我自己的进程有个掩码,系统的掩码,到底这个进程的掩码听谁的?

就近原则,现在我在自己程序设置掩码,肯定是我自己的比系统的更亲

 此时设置成功

再来看一下这个open函数的返回值是多少?

 

记住这个3~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

  • close 

与open对应的就是close()

 

这个fd是文件描述符~~~究竟他是什么我们后面惠更清晰的讲解,刚才open的返回值就是fd=3 

 那么输入3给close,他就能找到对应的被打开的文件,从而关闭他

是不是感觉很神奇,fd就像密码一样

  • write 

 把buf中n个字节内容写入到fd对应的文件中

最后返回实际写入的字符数,如果写入失败返回-1并且设置errno变量

如果成功返回值>=0

简单演示一下

 

要不要+1是考虑要不要加上\0

此时没+1 

很明显是正确的

为什么不加?

因为字符串以\0结尾是C语言的规定不是文件的规定!!!!! 

  • read

 把文件中的内容读到buf中,读取count字节的内容 

最后的返回值还是实际读到的字节数,暂时我们无法按行读取只能整体读

在使用系统接口进行IO的时候一定要注意\0的问题

 

用之前的log.txt里面有hello\n 

 


那么语言和我们今天讲的接口有什么关系?

库函数的底层调用:系统调用

小总结:

fopen,fclose,fwrite/fputs,fread/fgets ——库函数

open,close,write,read——系统调用

他们的关系式库函数封装了系统调用!!!!!!!!!!!


文件描述符

fd(file descriptor)

任何一个进程启动的时候默认会打开当前进程的三个文件

标准输入——键盘文件

标准输出——显示器文件

标准错误——设备文件——显示器文件

 结果

 

说好的标准输出和标准错误都会向显示器打印,但是他们本质不一样

还记不记得我们之前在open的时候返回值fd=3

那么为什么是3,不是0 ,1,2

并且还发现

  

 这些被打开文件的fd居然是连续的!!!!!!!

这让人不禁想起数组

因为我觉得这些被打开文件肯定也是有人帮我维护的,维护就需要一定的数据结构,那我猜测这种数据结构就是数组!

真的 是这样!

因为0 1 2已经被操作系统占用了。所以只能从3开始

文件描述符:本质是数组下标 

是什么数组的下标?

 

当进程要打开一个文件时:

OS在内存中创建一个struct_file对象(为了把磁盘中的对应文件加载到内存)

找到是哪个进程要打开文件,用这个进程的struct files_struct* files找到struct files_struct 进而找到内部fd_array[]数组,从0下标向下遍历到一个没被占用的下标(这里很重要,星号标记*)

0 1 2默认被系统占用,找到3(假设)把创建好的struct_file对象的地址填入下标为3的数组中,向应用层返回文件描述符3!!!!

所以上层只要拿到3就可以像密码一样打开后面的很多函数(系统调用) ,但是作为用户他并不知道OS为他做了什么~

我们所谓的IO类(read,write函数)本质就是拷贝函数——用户空间和内核空间进行数据的来回拷贝

具体过程如下

那么为什么要用fd_argv[ ]里面放file* 的方法做映射?

实现模块解耦

 

如何理解一切皆文件?

下回分说~ 

 

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

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

相关文章

【数据结构】结构最复杂实现最简单的双向带头循环链表

【数据结构】结构最复杂实现最简单的双向带头循环链表 一、前言二、目标三、实现1、初始化工作2、尾插2.1、图解思路2.2、代码实现 3、尾删3.1、图解思路3.2、代码实现 4、打印链表5、头插5.1、图解思路5.2、代码实现 6、头删6.1、图解思路6.2、代码实现 7、查找8、随机插入8.1…

数据结构与算法基础(青岛大学-王卓)(2)

第二弹火爆来袭中 这波是单链表的内容整理&#xff0c;废话不多说&#xff0c;上小龙虾呀(又到了龙虾季节了&#xff0c;哎&#xff0c;口水直流了~~) beautiful的分割线 文章目录 第二弹火爆来袭中这波是单链表的内容整理&#xff0c;废话不多说&#xff0c;上小龙虾呀(又到了…

【致敬未来的攻城狮计划】— 连续打卡第二十七天:瑞萨RA RA2E1 的 BTN触摸按键

文章目录 由于一些特殊原因&#xff1a; 系列文章链接&#xff1a;&#xff08;其他系列文章&#xff0c;请点击链接&#xff0c;可以跳转到其他系列文章&#xff09;或者参考我的专栏“ 瑞萨MCU ”&#xff0c;里面是 瑞萨RA2E1 系列文章。 24.RA2E1的 DMAC——数据传输 25.R…

DB2_sql_问题

db2新增字段指定顺序 这个是不能做到的&#xff0c;除非把表删除重新创建的&#xff01; 原理是这样子的&#xff1a;当你创建表时系统会记录下你的SEQ-ID,就是字段的顺序号&#xff0c;这个是根据字段先后顺序来生成的&#xff0c;系统默认显示的时候也是根据这个来的&#x…

linux:工具(命令)vi、vim文本编辑器详解。

linux:工具(命令)vi/vim文本编辑器详解。 因此&#xff0c;本质上vi和vim是同种东西&#xff0c;后面也会合起来说&#xff0c;但是使用上会使用vim&#xff0c;因为vim是加强版。 使用形式&#xff1a; 无论退出还是进入都需要去到 “命令模式”。 当使用vi/vim时就会进入“命…

「高性能MySQL」读书笔记(1)- MySQL架构

一、前言 本系列主要是记录阅读「高性能MySQL」期间笔记&#xff0c;记录在日常使用中忽略的知识、模糊的点&#xff0c;主要面对有一定MySQL使用经验的开发者。 本文是针对于MySQL一些基础定义的解释说明&#xff0c;会非常浅显通俗易懂。 二、MySQL的逻辑架构 简单梳理My…

PCL学习九:Registration-配准

参考引用 Point Cloud Library黑马机器人 | PCL-3D点云 1. 点云中的数学 函数求导 对于函数 f ( x ) x 2 f(x)x^2 f(x)x2 其一阶导数也是 x x x 的函数&#xff1a; d f d x 2 x \frac{df}{dx}2x dxdf​2x其二阶导为常数&#xff0c;与 x x x 无关&#xff1a; d 2 f d x…

【漏洞分析】CVE-2021-0920 Linux内核垃圾回收机制中的竞争UAF漏洞

漏洞发现&#xff1a;该漏洞早在2016年被 RedHat 内核开发人员发现并披露&#xff0c;但 Linux 内核社区直到 2021 年重新报告后才对该漏洞进行修补&#xff08;patch&#xff09;。Google的威胁分析小组&#xff08;Threat Analysis Group&#xff09;发现该漏洞在野外被使用&…

shell脚本----基础命令

文章目录 一、sort命令二、uniq命令三、 tr命令四、cut命令 一、sort命令 sort命令以行为单位对文件内容进行排序&#xff0c;也可以根据不同的数据类型来排序&#xff0c;比较的原则是从首字符向后&#xff0c;一次按ASCII码的值进行比较&#xff0c;最后按序输出。 ASCII码…

【P17】JMeter 边界提取器(Boundary Extractor)

文章目录 一、准备工作二、测试计划设计 一、准备工作 慕慕生鲜&#xff1a; http://111.231.103.117/#/login 进入网页后&#xff0c;登录&#xff0c;页面提供了账户和密码 搜索框输入“虾” 右键检查或按F12&#xff0c;打开调试工具&#xff0c;点击搜索 二、测试计划设…

详细版易学版TypeScript - 元组 枚举

一、元组(Tuple) 数组:合并了相同类型的对象 const myArr: Array<number> [1, 2, 3]; 元组(Tuple):合并了不同类型的对象 // 定义元组时就要确定好数据的类型&#xff0c;并一一对应 const tuple: [number, string] [12, "hi"]; // 添加内容时&#xff0c;不…

SQLIST数据库编程

目录 数据库简介 1.常用数据库 2. SQLite基础 3.创建SQLite数据库 虚拟中sqlite3安装 基础SQL语句使用 sqlite3编程 数据库简介 1.常用数据库 大型数据库 &#xff1a;Oracle 中型数据库 &#xff1a;Server是微软开发的数据库产品&#xff0c;主要支持windows平台 小型数据库…

( 位运算 ) 190. 颠倒二进制位 ——【Leetcode每日一题】

❓190. 颠倒二进制位 难度&#xff1a;简单 颠倒给定的 32 位无符号整数的二进制位。 提示&#xff1a; 请注意&#xff0c;在某些语言&#xff08;如 Java&#xff09;中&#xff0c;没有无符号整数类型。在这种情况下&#xff0c;输入和输出都将被指定为有符号整数类型&a…

Vue.js自定义指令及用Vue实现简单的学生信息管理系统

目录 一、自定义指令v-mycolor 自定义指令生命周期&#xff1a; 二、使用钩子函数的自定义指令 三、Vue实现简单的学生信息管理系统 除了核心功能默认内置的指令&#xff0c;Vue.js允许注册自定义指令。添加一个自定义指令&#xff0c;有两种方式&#xff1a; &#xff08;1…

Redis 常见命令

一、redis中的常见数据结构 Redis共有5种常见数据结构&#xff0c;分别字符串&#xff08;STRING)、列表&#xff08;LIST&#xff09;、集合&#xff08;SET)、散列&#xff08;HASH&#xff09;、有序集合&#xff08;ZSET)。 二、redis中字符串(String)介绍 String 类型是…

PS网页版设计工具有哪些?

Photoshop是平面设计领域的老熟人&#xff0c;也是许多设计师的启蒙设计软件。然而&#xff0c;Photoshop的功能繁多&#xff0c;需要设计师具备较强的软件操作能力。在我们以为会和Photoshop一直相爱相杀的时候&#xff0c;一款专注于用户界面的矢量设计软件——即时设计&…

荔枝派Zero(全志V3S)驱动开发之RGB LCD屏幕显示jpg图片

文章目录 前言一、jpeglib 库移植1、jpeglib 库下载2、安装 jpeglib 库 二、jpeg 图片解压缩过程和压缩过程1、jpeg 解压缩过程2、jpeg 压缩过程 三、编译 C 源码1、源码展示2、拷贝需要用到的头文件3、编译 C 代码 四、验证测试1、拷贝相关文件到开发板2、显示图片 前言 由于…

深入了解Dubbo SPI 工作机制——@Adaptive(6)

Adaptive这个注解就是适配策略&#xff0c;我都是称呼为最佳适配子类&#xff0c;或者最佳适配类。就是找到最佳的子实现类的&#xff0c;其实就是默认的类。这个注解可以打在类上方&#xff0c;那么dubbo SPI机制通过接口获取实例类&#xff0c;就是获取到有Adaptive注解的实现…

WooCommerce商城开发:高性能订单存储数据库模式

这是一系列深入探讨的第一部分&#xff0c;专门用于解释高性能订单存储数据库模式的实施。 与1 月份提出的版本相比&#xff0c;数据库模式的变化很小。我们在不同的地方添加和删除了几列&#xff0c;但整体表结构与第一个提案中描述的相同&#xff1a; 我们在此项目中添加了4…

51单片机(九)LED点阵屏

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…