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

news2024/11/26 1:35:57

⭐⭐⭐个人主页⭐⭐⭐

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

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 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

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

缓冲区的好处

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

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

认识磁盘

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

盘面上可以划分为多个磁道,每个磁道又可以划分为多个扇区,,扇区是硬盘的最小的存储单元,一般是存储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.coloradmin.cn/o/1826280.html

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

相关文章

虚函数表共享和生成

每个类有不同的虚表&#xff0c;相同的类使用相同的虚表 模拟动态绑定的一个过程

【Apache Doris】周FAQ集锦:第 6 期

【Apache Doris】周FAQ集锦&#xff1a;第 6 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目&#xff01; 在这个栏目中&#xff0c;每周将筛选社区反馈的热门问题和话题&#xff0c;重点回答并进行深入探讨。旨在为广大用户和…

C++11左值、右值

知识回顾&#xff0c;详解引用 简单概括&#xff0c;引用就是给已存在对象取别名&#xff0c;引用变量与其引用实体共用同一块内存空间 左右值区分 注意&#xff1a;不一定左边的都是左值&#xff0c;右边的都是右值 左边的也可能是右值&#xff0c;等号右边的也可能是左值 …

大数据工程师如何做到数据可视化?

好的数据可视化作品都是通过不断的数据对比分析实战出来的。 今天给大家带来一篇大数据工程师干货&#xff0c;从多角度解析做数据可视化的重要性&#xff0c;并解读一些适用的应用场景。大数据工程师们刷到这篇文章时一定要进来看看&#xff0c;满满的干货。 目录 1. 什么是数…

中望CAD 2025 (ZW3D2025) 简体中文修改版

名称&#xff1a;中望CAD 2025 (ZW3D2025) 简体中文修改版 描述&#xff1a;一款三维CAD设计工具&#xff0c;运行破解补丁ZW3D2025-2024-Patch执行修补。 链接&#xff1a;夸克网盘分享 &#x1f4c1; 大小&#xff1a;3.2GB &#x1f3f7; 标签&#xff1a;#PC软件 #CAD #设…

为什么笔记本电脑触控板不工作?这里有你想要的答案和解决办法

序言 你的笔记本电脑触控板停止工作了吗?值得庆幸的是,这个令人沮丧的问题通常很容易解决。以下是笔记本电脑触控板问题的最常见原因和修复方法。 触控板被功能键禁用 大多数(如果不是全部的话)Windows笔记本电脑都将其中一个功能键用于禁用和启用笔记本电脑触控板。按键…

【Arthas案例】某应用依赖两个GAV不同但包含两个相同全限定类名StaticLoggerBinder,引起log4j.Level类找不到异常

3分钟内解决问题 两个不同的GAV依赖冲突&#xff0c;包含相同全限定类名&#xff0c;引起ClassNotFoundException Maven依赖的三坐标体系GAV(G-groupId&#xff0c;A-artifactId&#xff0c;V-version) 【案例1】某应用依赖两个GAV不同的jar&#xff0c;但包含两个相同全限定类…

Jmeter多个请求按照比例并发压测的几种方式

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、需求 在压测的过程中&#xff0c;为了能够压测整个链路&#xff0c;通常需要多个接口进行并…

OpenAI Assistants API:如何使用代码或无需代码创建您自己的AI助手

Its now easier than ever to create your own AI Assistant that can handle a lot of computing tasks for you. See how you can get started with the OpenAI AI Assistant API. 现在比以往任何时候都更容易创建您自己的AI助手&#xff0c;它可以为您处理许多计算任务。了…

微信公众号打通与登录的实现

今天实现一下与微信公众号进行对接&#xff0c;通过扫描二维码的方式来进行注册与登录&#xff0c;获取用户的微信唯一标识作为用户的username&#xff0c;下面我们开始编写。 骨架建立&#xff1a; 建包&#xff1a; 第一步还是先将骨架建好&#xff0c;与网关骨架差不多&a…

树莓派4B_OpenCv学习笔记9:图片的腐蚀与膨胀

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; 图像的膨胀与腐蚀一般用于灰度图或者二值图,今日便来学习…

基于python-CNN卷积网络训练识别牛油果和猕猴桃-含数据集+pyqt界面

代码下载地址&#xff1a; https://download.csdn.net/download/qq_34904125/89383066 本代码是基于python pytorch环境安装的。 下载本代码后&#xff0c;有个requirement.txt文本&#xff0c;里面介绍了如何安装环境&#xff0c;环境需要自行配置。 或可直接参考下面博文…

目前市面上DIY高端空心耳机壳使用的透明原材料是什么?

目前市面上DIY高端空心耳机壳使用的透明原材料是什么&#xff1f; DIY制作耳机壳的UV树脂胶是一种单组份、通过紫外线光固化的胶粘剂&#xff0c;具有低能量固化、收缩低、发热量低、高透明、耐盐酸、耐黄变好、高硬度、韧性好、成型好等特点。这种胶粘剂非常适合用于制作耳机壳…

Redis 主从集群 哨兵原理

一. Redis 主从集群 1.1 基本概念 主从架构&#xff1a;Redis主从集群采用“一主多从”的架构模式&#xff0c;其中主节点&#xff08;Master&#xff09;负责处理客户端的读写请求&#xff0c;而从节点&#xff08;Slave&#xff09;则负责处理读请求。这种读写分离的设计使…

Pytest 读取excel文件参数化应用

本文是基于Pytest框架&#xff0c;读取excel中的文件&#xff0c;传入页面表单中&#xff0c;并做相应的断言实现。 1、编辑媒体需求 首先明确一下需求&#xff0c;我们需要对媒体的表单数据进行编辑&#xff0c;步骤如下&#xff1a; 具体表单如下图所示 1、登录 2、点击我…

618洗地机全网热门推荐,跟着买错不了

步入酷热夏天&#xff0c;家中的清洁工作也迎来了新的挑战。天气炎热&#xff0c;细菌、异味滋生的困扰让日常打扫变得不再轻松&#xff0c;这时一台高性能的洗地机就成了提升生活品质的必备良品。不同于洗地机的技术与类别繁多&#xff0c;洗地机虽原理不复杂&#xff0c;但在…

堆栈溢出的攻击 -fno-stack-protector stack smash 检测

在程序返回的一条语句堆栈项目处&#xff0c;用新函数的起始地址覆盖&#xff0c;将会跳转到执行新函数。 现在系统对这个行为做了判断&#xff0c;已经无法实施这类攻击或技巧。 1&#xff0c;测试代码 #include <stdio.h> void cc() {printf("I am cc( )\n"…

【AI+编程】工作日常场景随时可以AI编程,记一个问答SQL快速导出数据日常示例

今天有个场景&#xff0c;我们有个老项目&#xff0c;由于历史原因差不多1年多没使用了&#xff0c;恰巧客户紧急情况要使用。因为当时没有需求&#xff0c;所以V1.0上线后 就没做更新。 需求很简单&#xff1a;我们假定 项目问题表、客户表、问题答案表&#xff0c; 实时查询…

VisionOS的未来愿景:苹果VisionPro创业者的愿望清单

随着苹果公司在增强现实(AR)领域的不断探索,VisionPro作为其前沿产品,已经开始展现出改变我们与数字世界互动方式的潜力。作为一名VisionPro创业者,对未来VisionOS的更新充满了期待,并提出了一系列愿望清单,这些愿望不仅代表了个人的需求,也反映了用户社区对苹果AR生态的…

【ETAS CP AUTOSAR基础软件】DET、Bfx、CRC、ComStack、rba_ArxmlGen模块详解

文章包含了AUTOSAR基础软件&#xff08;BSW&#xff09;中DET、Bfx、CRC、ComStack、rba_ArxmlGen模块相关的内容详解。本文从AUTOSAR规范解析&#xff0c;ISOLAR-AB配置以及模块相关代码分析三个维度来帮读者清晰的认识和了解DET、Bfx、CRC、ComStack、rba_ArxmlGen。文中涉及…