【linux】认识“文件”的本质,理解“文件系统”的设计逻辑,体会linux优雅的设计理念


⭐⭐⭐个人主页⭐⭐⭐

~~~~~~~~~~~~~~~~~~

C站最❤❤❤❤❤❤博主

~~~~~~~~~~~~~~~~~~~

​♥东洛的克莱斯韦克-CSDN博客

~~~~~~~~~~~~~~~~~~~~

嗷呜~

✌✌✌✌

萌妹统治世界~

🎉🎉🎉🎉

✈✈✈✈相关文章✈✈✈✈

💤【Linux】进程地址空间-CSDN博客💤💤💤

​​💤💤💤【linux】进程控制——进程创建,进程退出,进程等待-CSDN博客​​💤💤

【linux】在linux操作系统下快速熟悉开发环境并上手开发工具——体验不一样的开发之旅_熟悉linux下开发-CSDN博客

目录

概述

文件描述符

0 1 2 文件描述符

文件描述符分配规则

重定向原理概述

dup2系统调用

缓冲区

用户级缓冲区

内核缓冲区

缓冲区的好处

认识磁盘

磁盘的寻址

磁盘的抽象化理解

文件系统

重新认知目录

上层数据如何流动到磁盘中


概述

文件 == 内容  +  属性

文件的内容就是在文件中写入的数据

要怎么理解 “ 属性 ” 一词呢?如果有一个苹果,怎么才能认识到它是一个苹果呢,我们很难说清一个苹果的本质到底是什么,但可以通过它的形状,色泽口感来判断这是一个苹果。这就是一个苹果的属性,一个事物的属性可以帮助我们认识 “ 它 ” 是什么

文件的属性能帮我们认识一个文件

文件的基本属性可以用 ll 指令查看

一个文件的基本属性:文件类型,权限,硬链接数,拥有者,所属组,文件内容大小,最近一次被修改的时间

当我们只创建了文件,并未在文件中写入数据,该文件的大小也不为 0 。该文件的相关属性也会被保存到磁盘中。

文件会被谁访问呢?

答案是进程,进程创建文件,进程打开文件,进程对文件做写入。

认清文件的各种操作本质是认清进程和文件的关系。进程和文件之间是怎么联系起来的呢?

文件保存在哪里呢?

答案是磁盘,磁盘的物理结构是怎样的?怎么做到从从硬件层到软件层的抽象化呢?

文件是怎么被管理的呢?

答案是文件系统,什么是文件系统呢?它是怎么把文件管理起来的呢?

上述问题是该文章的主框架。此外,还会谈一谈周边问题:重定向原理,缓冲区,内存管理(基本认知),目录,以及Linux下一切皆文件的话题

回答了上述问题就可以谈一谈应用层的数据如何通过操作系统写入磁盘的

注:本文旨在让读者对文件有进一步的认知,打消对文件的零认知。并未涉及对文件系统的专业讲解以及对linux文件系统源码级理解。

文件描述符

进程要打开某个文件时,操作系统会在内存中创建file结构体来维护文件的属性。上文已经提到属性的概念。

一个进程能打开多个文件,所以进程和文件的对应关系是一对多

所以一个 task_struct(进程控制块,用来描述进程属性的结构体)可以对应多个file结构体。

task_struct中有一个指针指向一个files_struct的数组,而数组中存的是的file*类型的指针,这样就实现了一个进程对应多个文件。

files_struct数组的下标就是文件描述符

所有的操作系统提供的接口(系统调用)中只认文件描述符

有关文件系统调用接口(用法可用man手册查看):open  close  read  write  lseek

语言层对文件操作的函数和系统提供的文件接口关系如下

语言层提供的函数必须封装文件描述符和系统调用

0 1 2 文件描述符

操作系统会默认打开三个流:标准输入   标准输出   标准错误

标准输入对应键盘文件

标准输出和标准错误对应显示器文件 

为什么硬件也可以称为文件会在文章的最后谈,即linux下一切皆文件的话题

0号文件描述符代表代表键盘文件,1号和2号文件描述符代表显示器文件

files_struct数组中,0下标存的file*的指针指向键盘文件的file结构体,而1下标和2下标的的file*的指针指向显示器文件的file结构体

1号和2号文件描述符都指向显示器文件。在file结构体中会维护一个引用计数,每多一个文件描述符指向自己引用计数加加,反之减减。引用计数为 0 就释放该结构体资源。

文件描述符分配规则

files_struct数组中找最小并且未被使用的文件描述符,分配给新的file*指针。

重定向原理概述

如果关掉一号文件描述符,根据文件描述符分配规则,1号文件描述符会被分配给新创建的文件。但上层接口不知道1号描述符已经不指向显示器文件,但该接口依然会向新的文件输出。对显示器文件输出数据变成对其他文件输出数据,这种现象成为输出重定向

如果0号描述符被改变指向,本来该往显示器文件读取数据转为从其他文件读取数据,这种现象成为输入重定向

如下是输出重定向代码示例

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{close(1);int fd = open("myfile", O_WRONLY|O_CREAT, 00644);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);fflush(stdout);close(fd);exit(0);
}

dup2系统调用

头文件 :#include <unistd.h>
函数原型 :int dup2(int oldfd, int newfd);

功能:把oldfd文件描述符的file*指针拷贝给newfd文件描述符的file*指针,可以不用关闭文件描述符也能完成输入,输出重定向

代码示例

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {int fd = open("./log", O_CREAT | O_RDWR);if (fd < 0) {perror("open");return 1;}close(1);dup2(fd, 1);for (;;) {char buf[1024] = {0};ssize_t read_size = read(0, buf, sizeof(buf) - 1);if (read_size < 0) {perror("read");break;}printf("%s", buf);fflush(stdout);}return 0;
}

缓冲区

缓冲区刷新策略:

1.直接刷新     2.按行刷新     3.缓冲区满了在刷新    4.进程退出时强制刷新

用户级缓冲区

在C语言中,对文件操作时都绕不开一个东西——FILE

FILE是一个结构体,里面封装了文件描述符用户缓冲区的相关的属性。

可以在/usr/include/stdio.h查看, typedef struct _IO_FILE FILE
struct _IO_FILE {int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags//缓冲区相关/* The following pointers correspond to the C++ streambuf protocol. *//* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */char* _IO_read_ptr; /* Current read pointer */char* _IO_read_end; /* End of get area. */char* _IO_read_base; /* Start of putback+get area. */char* _IO_write_base; /* Start of put area. */char* _IO_write_ptr; /* Current put pointer. */char* _IO_write_end; /* End of put area. */char* _IO_buf_base; /* Start of reserve area. */char* _IO_buf_end; /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base; /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno; //封装的文件描述符
#if 0int _blksize;
#elseint _flags2;
#endif_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary *//* 1+column number of pbase(); 0 is unknown. */unsigned short _cur_column;signed char _vtable_offset;char _shortbuf[1];/* char* _save_gptr; char* _save_egptr; */_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

内核缓冲区

用户缓冲区是由进程维护的一块空间,该缓冲区不能直接与外设交互,需要刷新到内核缓冲区,内核缓冲区与外设交互的行为叫做IO

如果通过函数向外设输出数据,该数据需要经过用户缓冲区和内核缓冲区。如果通过系统调用向外设输出信息,该数据会被直接刷到内核缓冲区。

缓冲区的好处

用户缓冲区:提高函数的效率,只需把数据交给用户缓冲区即可返回。

内核缓冲区:提高了效率,因为内核可以直接与硬件交互,而无需频繁地在用户和内核空间之间切换

认识磁盘

磁盘的重要的两个结构是盘片磁头,盘片上有磁性物质,可以记录而进程数据。磁头用来对二进制数据做存取。

盘面上可以划分为多个磁道,每个磁道又可以划分为多个扇区,,扇区是硬盘的最小的存储单元,一般是存储512字节(byte)

磁盘不仅是外设,而且还是机器设备。相同数据量下磁头移动的次数越少磁盘的效率越高。

磁盘的寻址

对磁盘上的数据做存取,首先要定位哪个盘面,然后定位哪个磁道,然后在定位哪个扇区

通过确定盘面,磁道,扇区来定位磁盘上的数据,这种寻址方式称为CHS寻址。

磁盘的抽象化理解

如果把所有磁道展开成一条直线,每个扇面在这条直线上均匀分布。像数组一般,每个扇面都有唯一的编号。这种编号的方式称为 LBA寻址

 LBA地址=(柱面编号×硬盘磁头的总数+磁头编号)×扇区数+扇区编号-1
扇区数为每磁道的扇区数

文件系统

已经可以通过LBA地址访问磁盘中的数据,那么怎么管理这些数据呢

磁盘大小

 台式机和笔记本电脑中使用的传统机械硬盘的容量范围很广,从几百GB到数十TB不等。常见的容量包括1 TB、2 TB、4 TB、8 TB乃至更大

磁盘的分区

指的是将一个物理磁盘的存储空间逻辑地划分为多个独立的部分。每个这样的部分被称为一个分区,它在操作系统中表现为一个单独的驱动器或卷。分区允许用户组织数据,例如,可以将操作系统、应用程序和用户数据分别存储在不同的分区上,这样即使某个分区出现问题,其他分区的数据仍然可以保持安全

举个简单的例子,在Windows系统下,所谓的C盘,D盘,E盘等就属于磁盘的分区

block
Linux ext2文件系统,磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。 只需管理好每一个block就可以管理好整个磁盘的数据了

怎么管理好一个block呢

介绍
Super Block 超级块, 存放文件系统本身的结构信息。
记录的信息主要有:bolck inode 的总量,未使用的block inode 的数量,一个 block inode 的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block 的信息被破坏,可以说整个文件系统结构就被破坏了
Group Descriptor Table :块组描述符,描述块组属性信息
Block Bitmap Block Bitmap 中记录着 Data Block 中哪个数据块已经被占用,哪个数据块没有被占用
inode Bitmap :每个 bit 表示一个 inode 是否空闲可用
inode Table 节点表, 存放文件属性 如 文件大小,所有者,最近修改时间等
Data blocks :数据区,存放文件内容
详解
Data blocks中存放的是文件的内容,以 八个扇区为一个数据块(大小是4KB),每个数据块都有自己的编号。

inode Table是一张节点表,每个节点对应一个文件的属性。每一个文件属性只对应一个inode,系统会为每个inode分配一个唯一的编号。

文件内容和文件属性是分开管理的。那么怎么通过inode找到在Data blocks 中的数据呢?

inode结构体中不仅会维护文件的属性,还会维护一个数组。数组的大小为15。数组中存的是Data blocks中的数据块编号,0到11下标的编号为一级索引,12下标和13下标的编号为二级索引,14号下标的编号为三级索引。

一级索引:对应的数据块的内容就是文件的内容

二级索引:对应的数据块的内容是一级索引的数据块的编号

三级索引:对应的数据块的内容是二级索引的数据块的编号

如下是简单的示意图,细节部分并不准确,仅供参考

Block Bitmap中用比特位映射的方式(位图)来代表哪一个数据块是否被使用,1代表使用,0代表未使用

inode Bitmap中用比特位映射的方式(位图)来代表哪一个inode是否被使用,1代表使用,0代表未使用

Super Block用来记录整个分区文件系统的情况,它不会在每一个block中保存但会有备份

删除文件

在计算机中,删除 == 可以被覆盖

把一个文件删除时,并不会对文件对应的数据块做写入,也就是不会对文件的内容做清空。操作系统只会把Block Bitmapinode Bitmap中位图的由 1 置 0 即可,所以一个被删除的文件是可以被恢复出来的,因为文件的内容并未被清空。

创建文件

核心工作如下:
在inode表中找到找空闲的inode,在这个inode中填入文件的属性
在数据块中写入 (如果有写入需求)
把位图中相关的信息由0 置 1
格式化
格式化的工作是把文件系统中  Super Block Group Descriptor TableBlock Bitmapinode Bitmapinode Table,的相关字段恢复为初始状态 。但中 Data blocks的数据块不会被写入,所以,即使整个磁盘被格式化了,其数据也可以恢复出来。(理论上哦~   代价比较大)

重新认知目录

目录文件的数据块中存的是文件名和inode编号的映射

linux中不会根据一个文件名查找一个文件,只会通过inode编号查找这个文件。

但我们只给了系统路径和文件名,它是怎么找到该文件的呢?

想要找到当前目录下的文件,就需要知道当前目录和inode编号的映射关系,因此就必须读取当前目录的数据块。那就需要找到当前目录的inode,因此就必须读取上级目录的数据块,因此就必须知道上级目录的inode,以此类推到根目录,根目录的文件名和inode的关系是确定的,就能找到根目录,并读取根目录的数据块,然后就能找到下级目录的inode,进而读取下级目录的数据块,一直向下推,直到找到目标文件的inode编号。

这样的递归式的寻找会有效率上的问题,所以系统会把常用的目录缓存起来,这个缓存叫dentry缓冲

操作系统会把相关文件系统的字段加载到内存,用用结构体维护起来,然后用链表维护起来,这样做是为了加速查找,不然查找文件的时候就需要先从磁盘读取,速度太慢。

上层数据如何流动到磁盘中

调用printf向显示器文件输出数据。数据会被刷到用户缓冲区。

在file结构体中会有一个指针指向address_space结构体,该结构体中会维护一颗字典树,用来建立数据和内存的映射关系,按4KB大小建立映射。然后被刷入内存缓冲区

被刷入缓冲区的数据需要建立IO请求,缓冲区中有很多IO请求,每一个请求会用结构维护起来,再用配套的算法使这些数据以最小的代价刷入磁盘——因为磁盘使机器设备

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

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

相关文章

REST风格

黑马程序员Spring Boot2 文章目录 1、REST简介1.1 优点1.2 REST风格简介1.3 注意事项 2、RESTful入门案例 1、REST简介 1.1 优点 隐藏资源的访问行为&#xff0c;无法通过地址的值对资源适合中操作书写简化 1.2 REST风格简介 按照RST风格访问资源时使用行为动作区分对资源进…

unity跑酷游戏(源码)

包括&#xff1a;触发机关&#xff0c; 优化 fog的调试 效果 碰到障碍物游戏时间暂停&#xff08;挂载到障碍物上&#xff09; 上面需要有碰撞体 游戏物体上需要有标签 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Barri…

SSM考研咨询app-计算机毕业设计源码05262

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设考研咨询app。 本设计…

系统运维联盟 5 月会议召开,围绕“进展、规划与合作”展开讨论

2024 年 5 月 28 日&#xff0c;龙蜥社区系统运维联盟&#xff08;SOMA&#xff0c;以下简称“运维联盟”&#xff09;月度会议于线上召开&#xff0c;12 家运维联盟单位、 20 位代表出席&#xff0c;缺席 1 家。本次会议由龙蜥社区运营委员会副主席、运维联盟秘书处负责人金美…

使用Python和TCN进行时间序列预测:一个完整的实战示例

使用Python和TCN进行时间序列预测&#xff1a;一个完整的实战示例 时间卷积网络&#xff08;TCN&#xff09;已被证明在处理序列数据方面表现出色&#xff0c;尤其是在需要捕获长期依赖关系的任务中。在本文中&#xff0c;我们将通过一个简单的例子&#xff0c;展示如何使用Py…

24年最新版基础入门大模型辅助Python编程指南

今天这篇文章只会聊 Python 入门基础&#xff0c;如何通过大模型辅助Python 编程&#xff0c;在 后续的文章里慢慢聊。 一点点 python都不会。又想用大模型带飞&#xff0c;辅助 python 编程&#xff0c;提升数据分析能力和效率&#xff0c;怎么办&#xff1f; 一点都不需要担…

孟德尔随机化R包:TwoSampleMR和MR-PRESSO安装

1. 孟德尔随机化R包 看一篇文章&#xff0c;介绍孟德尔随机化分析&#xff0c;里面推荐了这两个R包&#xff0c;安装了解一下&#xff1a; Methods:Genome-wide association study (GWAS) data for autoimmune diseases and AMD were obtained from the IEU Open GWAS databas…

Three.js动效(第12辑):效果炫酷,但性能问题突出,如何破?

Three.js是一款强大的3D渲染引擎&#xff0c;但是在处理大量数据时&#xff0c;可能会出现性能问题。贝格前端工场结合过往经验&#xff0c;给大家几条性能优化的建议。 1. 减少渲染次数&#xff1a; 可以通过合并对象、使用InstancedMesh等方式减少渲染次数&#xff0c;从而…

Nginx+keepalived实现高可用

目录 主要功能 典型应用场景 优点 keepalived工作原理 Nginxkeepalived高可用实验 一. 环境准备 二. 下载并部署配置 对master和backup都操作 对master主机操作 对备用backup主机进行操作 验证当主节挂掉&#xff0c;VIP能否转义到备用机 "Keepalived" …

SpringBoot+Vue实现Excel文档导入和导出

1.准备工作 1.1.前端程序 在前端首先加上批量导出的按钮&#xff0c;如下 <el-button size"small" type"warning" plain click"exportData"> 批量导出 </el-button> 在添加了点击事件之后&#xff0c;在methods中要与之对应的添加上…

c#引用dll报错cs8370功能“本地函数特性“在c#7.3中不可用

cs8370:功能"本地函数特性"在c#7.3中不可用 解决方法&#xff1a; 代码放在form类里面

SJ703安全帽防静电测试仪

一、仪器用途 专门检测安全帽防静电性能。 二、仪器特征 1、携带使用轻便、量程宽广、读数准确&#xff0c;耐震性强等卓越优点 2、超上限时显示‘1’提示和低于下限时声响报警。 3、电池欠压时显示欠压符号“←”提示。 4、交流或直流&#xff08;电池&#xff09;供电任…

Java17 --- RabbitMQ之插件使用

目录 一、Federation插件 1.1、运行两个rabbitmq实例 1.2、启用插件 1.3、在下游端点添加上游端点 1.4、创建策略 1.6、测试 二、联邦队列 2.1、创建策略 2.2、创建交换机与队列 2.2.1、创建52000的队列与交换机 2.2.2、创建62000的队列 三、Shovel 3.1、启…

Echats-wordcloud 文字云图的踩坑点【Unknown series wordCloud】

在词云渲染时遇到渲染不出来的问题&#xff1a; 原因分析&#xff1a; 1、echart和wordcloud版本不匹配&#xff08;我的是匹配的&#xff09; 解决方案&#xff1a; 1、echart和wordcloud版本要匹配&#xff1a; echart4x 使用wordcloud1x版本 echart5x 使用wordcloud2x版本…

Echarts图表: 矩形树图都有哪些配置项,一文告诉你

Hello&#xff0c;本期和大家分享矩形树图的配置项&#xff0c;欢迎评论区和贝格前端工场互动交流。 一、矩形树图是什么 矩形树图是ECharts中的一种图表类型&#xff0c;用于展示树形结构的数据。矩形树图通过矩形的大小和位置来表示树形结构中节点的层次关系和数据的大小。…

实例化游戏物体的实例(生成游戏物体)

一、实例1&#xff1a;实例化 1、准备工作&#xff1a;制备预制体&#xff0c;命名。如Circle 2、Create Empty&#xff0c;名字自取。如&#xff1a;CirclePrefab 3、给CirclePrefab添加Test.cs public GameObject CirclePrefab; // 预制体变量&#xff0c;用于存储Circle预…

基于matlab的MTCNN(多任务卷积神经网络)人脸检测算法

关键词&#xff1a;Matlab&#xff1b;深度学习&#xff1b;多任务卷积神经网络&#xff1b;人脸检测&#xff1b; 背景 在不受约束的环境中&#xff0c;由于个体姿势的多样性、光照条件的变化以及潜在的遮挡问题&#xff0c;人脸检测和对齐任务面临诸多挑战。近期的研究表明…

Elasticsearch搜索引擎(高级篇)

3.1 查询语法 | 《ElasticSearch入门到实战》电子书 (chaosopen.cn) day09-Elasticsearch02 - 飞书云文档 (feishu.cn) 目录 第一章 DSL查询 1.1 基本语法 1.2 叶子查询 全文检索查询 精确查询 1.3 复合查询 算分函数查询 bool查询 1.4 排序 1.5 分页 基础分页 深度分…

numpy的基本操作

1.常用方法创建array print(np.array([1, 2, 3], dtype"f4"))# 32位浮点型 print(np.array([1.5, 2.2, 3]))# 默认浮点型 print(np.array([1, 2, 3, 4, 5], ndmin3))# 3维数组 print(np.array([range(i, i 5) for i in [1, 2, 3]]))# print(np.zeros(shape[5, …

从开源EPR产品Odoo学习

前言 一个先进、敏捷、经济高效、可快速扩展的Odoo免费开源企业信息化解决方案,让企业获得适应未来发展的长期创新和增长能力。 Odoo 的免费开源模式 让我们可利用无数开发人员和业务专家,在短短数年内,打造数百款应用。凭借强大的技术基础,Odoo 的框架是非常独特且优秀的…