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

 

⭐⭐⭐个人主页⭐⭐⭐

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

C站最❤❤❤萌❤❤❤博主

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

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

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

嗷呜~

✌✌✌✌

萌妹统治世界~

🎉🎉🎉🎉

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

 

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

 

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

 

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

 

 

7c37ab5fe14341a7ba0e73bc610c8777.png

目录

 

概述

文件描述符

0 1 2 文件描述符

文件描述符分配规则

重定向原理概述

dup2系统调用

缓冲区

用户级缓冲区

内核缓冲区

缓冲区的好处

认识磁盘

磁盘的寻址

磁盘的抽象化理解

文件系统

重新认知目录

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


 

概述

文件 == 内容  +  属性

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

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

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

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

510fd967d386456493ec029a00be8f7e.png

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

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

文件会被谁访问呢?

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

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

文件保存在哪里呢?

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

文件是怎么被管理的呢?

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

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

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

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

文件描述符

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

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

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

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

a9b7cc35c49a45749d5d096ee57e7627.png

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

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

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

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

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

38627beb0d3545b9bdda5f031b5411c1.png

0 1 2 文件描述符

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

标准输入对应键盘文件

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

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 0
 int _blksize;
#else
 int _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。

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

07fdcb68db444b5985b666fa72a8d3f3.png

 

缓冲区的好处

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

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

认识磁盘

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

a016368ecc94447e876756e333412dde.png

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

95b220980e6149888ebf6a84e0ed4a74.png

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

 

磁盘的寻址

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

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

 

磁盘的抽象化理解

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

1e0eb4df88484d7fa79353eb7982b28a.png

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

 

文件系统

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

磁盘大小

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

磁盘的分区

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

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

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

b1368dba0b4347bfbee3007d9cc56287.png

怎么管理好一个block呢

e71fc9c310224b93940c0b131f0096d9.png

介绍
 
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号下标的编号为三级索引。

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

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

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

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

635dbcf9258048e993858ed07460a5f6.png

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

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

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

删除文件

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

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

 

创建文件

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

 

重新认知目录

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

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

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

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

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

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

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

bc937ca226bc4f888f0fde0efa9dcfe3.png

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

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

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

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年的Top20 AI应用在近一年表现怎么样?

AI应用现在进入寒武纪大爆发时代&#xff0c;百花争艳。如果倒回到2023年初&#xff0c;那时候排名靠前的AI应用在一年多时间&#xff0c;发生了哪些变化&#xff1f;能带给我们什么启示&#xff1f; 在2023年1月&#xff0c;排名靠前20的AI应用是&#xff1a; DeepL&#xff…

MATLAB中与直方图有关函数的关系

histogram Histogram plot画直方图 histcounts 直方图 bin 计数 histcounts是histogram的主要计算函数。 discretize 将数据划分为 bin 或类别 histogram2 画二元直方图 histcounts2 二元直方图 bin 计数 hist和histc过时了。替换不建议使用的 hist 和 histc 实例 hist → \r…

Day54 JDBC

Day54 JDBC JDBC&#xff1a;SUN公司提供的一套操作数据库的标准规范&#xff0c;就是使用Java语言操作关系型数据库的一套API JDBC与数据库驱动的关系&#xff1a;接口与实现的关系 给大家画一个jdbc的工作模式图 1.JDBC的四大金刚 1.DriverManager&#xff1a;用于注册驱动 2…

【Quartus 13.0】NIOS II 部署UART 和 PWM

打算在 EP1C3T144I7 芯片上部署 nios ii 做 uart & pwm控制 这个芯片或许不够做 QT 部署 这个芯片好老啊&#xff0c;但是做控制足够了&#xff0c;我只是想装13写 leader给的接口代码是用VHDL写的&#xff0c;我不会 当然verilog我也不太会 就这样&#xff0c;随便写吧 co…

SUSTAINABILITY,SCIESSCI双检期刊还能投吗?

本期&#xff0c;小编给大家介绍的是一本MDPI出版社旗下SCIE&SSCI双检“毕业神刊”——SUSTAINABILITY。据悉&#xff0c;早在2024年1月&#xff0c;ElSEVIER旗下的Scopus数据库已暂停收录检索期刊SUSTAINABILITY所发表文章&#xff0c;同时重新评估是否继续收录该期刊。随…

Qwen2——阿里巴巴最新的多语言模型挑战 Llama 3 等 SOTA

引言 经过几个月的期待&#xff0c; 阿里巴巴 Qwen 团队终于发布了 Qwen2 – 他们强大的语言模型系列的下一代发展。 Qwen2 代表了一次重大飞跃&#xff0c;拥有尖端的进步&#xff0c;有可能将其定位为 Meta 著名的最佳替代品 骆驼3 模型。在本次技术深入探讨中&#xff0c;我…

零基础入门学用Arduino 第三部分(三)

重要的内容写在前面&#xff1a; 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。个人把这个教程学完之后&#xff0c;整体感觉是很好的&#xff0c;如果有条件的可以先学习一些相关课程&#xff0c;学起来会更加轻松&#xff0c;相关课程有数字电路…

python-基础篇-类与对象/面向对象程序设计-是什么

文章目录 定义一&#xff1a;面对对象是一种编程思想定义一&#xff1a;面向对象是一种抽象1、面向对象的两个基本概念2、面向对象的三大特性 定义一&#xff1a;你是土豪&#xff0c;全家都是土豪面向对象编程基础类和对象定义类创建和使用对象访问可见性问题面向对象的支柱 定…

C++初学者指南第一步---4.基本类型

C初学者指南第一步—4.基本类型 文章目录 C初学者指南第一步---4.基本类型1.变量声明2.快速概览Booleans 布尔型Characters 字符型Signed Integers 有符号整数Unsigned Integers 无符号整数Floating Point Types 浮点数类型 3.Common Number Representations 常用的数字表示常用…

用Copilot画漫画,Luma AI生成视频:解锁创意新玩法

近年来&#xff0c;随着人工智能技术的不断发展&#xff0c;各种创意工具也层出不穷。今天&#xff0c;我们就来介绍一种全新的创作方式&#xff1a;使用Copilot画漫画&#xff0c;再将漫画放入Luma AI生成视频。 Copilot&#xff1a;你的AI绘画助手 Copilot是一款基于人工智…

【Kubernetes项目部署】k8s集群+高可用、负载均衡+防火墙

项目架构图 &#xff08;1&#xff09;部署 kubernetes 集群 详见&#xff1a;http://t.csdnimg.cn/RLveS &#xff08;2&#xff09; 在 Kubernetes 环境中&#xff0c;通过yaml文件的方式&#xff0c;创建2个Nginx Pod分别放置在两个不同的节点上&#xff1b; Pod使用hostP…

TCP及UDP协议

tcp是点到点的&#xff0c;只有一条路径&#xff0c;到达顺序和发送顺序是相同的 回复的确认号是序发送端的序列号加上data的长度 1910 发送端的序列号也是那么算的 ack和下一个seq一样 那就没问题 三次握手四次挥手&#xff1a; 为啥是三次呢&#xff1f; 假如一次&#xf…

SpringBoot使用jasypt实现数据库信息的脱敏,以此来保护数据库的用户名username和密码password(容易上手,详细)

1.为什么要有这个需求&#xff1f; 一般当我们自己练习的时候&#xff0c;username和password直接是爆露出来的 假如别人路过你旁边时看到了你的数据库账号密码&#xff0c;他跑到他的电脑打开navicat直接就是一顿连接&#xff0c;直接疯狂删除你的数据库&#xff0c;那可就废…

学习笔记——网络管理与运维——SNMP(SNMP架构)

三、SNMP架构 1、SNMP结构概述 SNMP被设计为工作在TCP/IP协议族上&#xff0c;基于TCP/IP协议工作&#xff0c;对网络中支持SNMP协议的设备进行管理。所有支持SNMP协议的设备都提供SNMP这个统一界面&#xff0c;使得管理员可以使用统一的操作进行管理&#xff0c;而不必理会设…

基于Spring+Vue的前后端分离的计算器

麻雀虽小&#xff0c;五脏俱全 该项目已部署上线&#xff1a;http://calculator.wushf.top/ 并通过Gitee Go流水线实现持续部署。 需求分析 表达式求值 支持加减乘除四则运算、支持高精度 获取日志 Api文档定义 前后端分离&#xff0c;人不分离 通过Apifox定义接口细节&#…

「TCP 重要机制」三次握手四次挥手

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;计网 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 三次握手&四次挥手 &#x1f349;连接管理&#x1f34c;三次握手&#x1f34c;意义&#x1f34c;四次挥手&#x1f34c;TCP 状态转换…

深入分析 Android BroadcastReceiver (三)

文章目录 深入分析 Android BroadcastReceiver (三)1. 广播消息的优缺点及使用场景1.1 优点1.2 缺点 2. 广播的使用场景及代码示例2.1. 系统广播示例&#xff1a;监听网络状态变化 2.2. 自定义广播示例&#xff1a;发送自定义广播 2.3. 有序广播示例&#xff1a;有序广播 2.4. …

[算法刷题—二分法]寻找插入位置

题目展示: 本道题本身并不是很难,主要是学习和分析二分查找插入位置的方法。 首先大体上分为两种情况: 一.target在待查找的数组之中,返回对应值的下标索引。 二.target不在待查找的数组之中&#xff0c;需要返回target插入位置的索引(原数组有序) 第一种情况不难&#xff…

跟着AI学AI_08 NumPy 介绍

NumPy&#xff08;Numerical Python&#xff09;是一个用于科学计算的基础库&#xff0c;它为 Python 提供了支持大规模多维数组和矩阵 NumPy 介绍 NumPy&#xff08;Numerical Python&#xff09;是一个用于科学计算的基础库&#xff0c;它为 Python 提供了支持大规模多维数…

最新版点微同城源码34.7+全套插件+小程序前后端(含安装教程)

模板挺好看的 带全套插件 自己耐心点配置一下插件 可以H5可以小程序 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89394996 更多资源下载&#xff1a;关注我。