Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >探秘磁盘内部的储存方式,揭露文件在软硬件上的不同模式

探秘磁盘内部的储存方式,揭露文件在软硬件上的不同模式

作者头像
绝活蛋炒饭
发布于 2024-12-16 08:24:16
发布于 2024-12-16 08:24:16
19501
代码可运行
举报
文章被收录于专栏:绝活编程学习绝活编程学习
运行总次数:1
代码可运行

1 引言

  1. 进程中被打开的文件,被加载进了内存当中。
  2. 难道所由的文件都被打开,加载进了内存当中吗?--- 当然不是
  3. 那么那些没有被打开文件存储在哪里呢?---被储存在了磁盘和固态硬盘(SSD)上
  4. 4.那么那些在磁盘上的文件需不需要被操作系统管理呢?---当然需要啦
  5. 那么操作系统怎么样才能在磁盘上快速找到目标文件呢?

2 磁盘的机械结构

2.1 盘面

  1. 盘片:就是堆叠在一起的圆形金属片。
  2. 盘面:盘片表面涂上磁性物质,涂上磁性物质,可以存储数据的那一面就叫做盘面。但是,盘片也可以两面都涂上磁性物质,这样一个盘片就有了两个盘面。

2.2 磁道和扇区

  1. 磁道(又叫做柱面):盘面上一个个被划分出来的同心圆环,叫做磁道。
  2. 扇区:每一个磁道又被划分为一个个扇形,这一个扇形就称为扇区。

扇区一般就是操作系统进程I/O操作最小的单位。

既然,是作为最小单位,那么每一个扇区存储的内容应该是一样多的,但是,我们可以观察到每一个扇区的大小是不一样,那怎么办?

为了保证扇区的存储大小一致,所以,每一个不同磁道的扇区的存储数据密度是不一致的

2.3 柱面和磁头

柱面:就是由每一个盘面上半径相同的磁道组成的空心圆柱

磁头:每一个盘面上都会有点一个读取数据的机械结构(注意:磁头和盘面只是离得非常近,两者之间是不接触的)

磁头和盘片的运动轨迹:盘片是依靠中心圆中主轴上的马达高速转动。磁头则是横向运动(如下图)

两者之间保持一个合适的速度差,使得磁头可以扫过盘面的每一块区域。


3 磁盘的物理储存

3.1 CHS定位寻址法

如果,为了让磁盘找到目标文件,在硬件层面上是使用CHS定位寻址法。

  1. 先让磁头确定目标数据是在哪一个柱面(C)
  2. 再通过确定在哪一个磁道,这样就确认的使用哪一个磁头 (H)
  3. 最后在通过确定哪一个扇区(S)

这样通过柱面,磁头,扇区三个参数,就确定了数据的位置。

这样每一个文件,不就是多个扇区组成的吗。这样就确定文件的位置了


4 磁盘的逻辑存储

4.1 线性的存储空间

我们看到这种磁带的黑色长线就是,他储存数据的地方,通过转动中央的两个孔来实现对数据的读取。

由此,我们联想到可不可以把所有的磁盘空间抽象的转化为一个长数组,把对数据的增删查改转化为对数组的增删查改。

4.2 LBA地址

  1. LBA地址(Logical Block Addressing,逻辑块寻址):是将扇区编号转化为一维线性编号的逻辑寻址方式,即:它将磁盘上所有扇区编号为一个连续的线性序列。
  2. LBA地址是一个线性地址(单一的数字),用于唯一标识磁盘上的一个扇区,LBA地址从0开始,依次递增。
  3. 工作原理:LBA编址方式将CHS这种三维寻址方式转变为一维的线性寻址;在访问磁盘时,系统或者磁盘控制器直接指定从硬盘上的特定扇区读取或写入LBA地址,硬盘控制器负责将LBA值转化为实际的物理CHS值。
  4. 优点:简化了数据访问的过程,提高了系统的效率,支持更大的容量;因为它采用线性寻址的方式,因此不受物理结构的限制。
  5. 注:LBA地址是扇区数组的下标;在使用LBA地址进行磁盘访问时,LBA地址指向磁盘的一个逻辑扇区,即:LBA地址实际上是直接对扇区的索引,不是对数据块的索引。
  • 既然我们将磁盘抽象出来,那么依旧需要存在一个把扇区以数组下标的方式表示转化为以CHS方式表示(扇区的抽象位置 -> 扇区的物理位置)
  • 但是呢,OS觉得就是每次都只能读写512字节效率实在是太低了,所以就将I/O操作的最小单位设置为4KB

那么这样从抽象地址转化到具体的地址,要增加一步:LBA地址 * 8+(0,1,2,3,4,5,6,7)这样才能算出一个扇区在这个线性结构中的具体位置。

4.3 inode

Linux下文件的特点: 文件 = 属性 + 内容

肯定没问题的是,我们描述一个文件的属性,肯定是使用一个结构体,而且是一个统一的结构体(那么文件属性的大小就是确定的,是一个固定的值)

但是,文件的内容完全是随机的,根本就没有一个固定的大小。

所以,Linux在存储文件方面采用了属性和内容分开存储的方式

我们可以很明显的看到,在这个结构体中并没有文件名,在OS内部我们不用文件名来标识文件,我们采用inode编号来唯一标识该文件。

ll -i :显示文件inode编号

4.4 分区与分组

我们一个磁盘一般来说都是512GB和1TB的大容量的,直接要管理这么大一块的内存空间显然是非常困难的,所以我们可以采用一下分治的思想,将空间划分为一小块,一小块的,然后将管理逻辑复制到每一个小块上。

4.5.这10GB中具体的管理模式

4.5.1 inode Table(i节点表)

前文提到了inode 是一个存储文件属性的结构体,那么inode table就是一块存储inode的数组空间。


4.5.2 inode Bitmap(inode位图)

inode Bitmap 是一个对位图的应用,每一个比特位就对应这inode Table 里的数组下标,用0/1来标识,该块的数组下标的内存是否被使用。


4.5.3 Data Blocks (数据区)

Data Block 以4KB为基本大小的数组,用来存放文件的内容。


4.5.4 blocks Bitmap(块位图)

blocks Bitmap也是对位图的应用,每一个比特位于Data Blocks的数组下标一 一对应,用来表示这块内存是否被使用。


4.5.5 GDB (Group Descriptor Table)
  1. 块组描述符:是对文件系统中所有块组进行管理的数据结构,每个块组在GDT中都有一个对应的条目,这个条目包含了块组的关键信息,如:inode表、数据块、inode位图、块位图的位置。
  2. GDT是一个全局的数据结构,每个块组中并不包含一个单独的GDT完整副本,通常只存储在文件系统中块组0,它描述了文件系统中所有块组的信息。

4.5.6 SB (Super Block)(超级块)
  1. 超级块:是文件系统中一个全局的数据结构,即:对整个文件系统进行管理的数据结构,存放整个文件系统的结构信息,如:block、inode的数量,未使用用的block、inode的数量,最近一次挂载的时间,最近写入数据的时间等其他与文件系统相关的信息
  2. 超级块的位置:一个文件系统,对应一个Super Block,通常在块组0中内保存着,为了提高文件系统的可靠性和容错性,会在个别块组内且存储Super Block的副本。(就例如,按照千分之一的概率来存放Super Block ,每一千个存放Block Group 中有一个Super Block)

4.5.6 Boot Block

Boot Block:只存在0号盘面、0号磁道、1号扇区中,即:分组0前,其作用是辅助开机,如:引导OS启动、检测文件系统状态、加载其他引导程序等。


4.5.7 Block Group

Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子。


4.5.8 inode Table 内存储的文件内容,怎么和Data Block 内存储的文件

在结构体inode内部有一个 int block[15]的数组用来记录Data Block 数组中的数组下标。

在block[0,12]中的每一个位置记录的就是Data Block数组中的下标,记录的那个数组块,存储的也是文件内容。

很明显,如果每一个Block数组只能记录一个4KB的数据块,那一个文件能够存储的空间也不大。但是,由于属性的大小是固定的,我们也不好对数组进行扩容。

Block[12,14]这两块空间指向的Data Block中的4KB数据块中存储的数据不是文件内容,而是其他的4KB空间(这些4KB空间中存储的是文件内容)----- 这样就造成了类似于二级索引的结果。

而Block[15]这块空间则是采用三级索引,指向的4KB空间中存储的是Data Block 数组的下标,而这些数组下标的4KB空间,内部存的其他的Data Block 数组的下标,而这些数组下标所指向的空间才是存储着文件内容


5 文件名和目录

文件是不是一定会存在一个目录里面?----- 那是肯定的 那么目录是不是也是一个文件?---- 是的,目录也是一个文件 那么目录这个文件中存储的文件内容是什么呢?


5.1 目录中存储的文件内容

直接给出结论:目录中存放的内容就是文件名与文件inode的映射关系


5.2 重谈文件的增删改

对于文件的增删改操作,最开始都是要先归结于查,得先找到文件,才能对文件进行操作吧!


5.2.1 在文件系统中如何找到文件(即利用inode去找到文件的流程)
  1. OS一开始都会给每一个分组都会记录一个起始inode编号,利用这个起始inode编号与目标inode进行对比(具体方法就是:每一个分组内的文件数是已知的,通过起始inode编号和文件数得出一个范围,在这个范围里进行比较),确定自己在哪一个分组。
  2. 根据自己查找到文件的目的,即对文件进行增删改中的哪一项?在决定是去访问Block Group中的哪一块区域。
  • 删除文件:直接访问inode Bitmap,找到对应文件的比特位(将文件inode编号减去分组起始inode编号,得出该文件在这个inode Bitmap中对应哪一个比特位)直接将这个比特位置为0.不用去管Data Block 中的文件内容,等待下次要用到的时候直接覆盖式写入就行了。
  • 新建文件:首先,就得先访问inode位图,找到合适的(没有被使用的inode),再在i节点表找到对应的inode的节点,填上对应的文件属性,再去块位图找到合适的数据区的4KB储存块,建立链接,再写入数据,最后在目录里面建立inode编号与文件名的映射关系。
  • 修改文件:找到目标inode,找到对应数据块,修改文件,修改inode内部的文件属性,

5.3 路径

我们之前提到了inode实在分组里面是唯一的,但是,在分区中inode是不唯一的,所以,我们如何在查找文件的时候通过文件名,来准确得出那个文件是我们需要的。

5.3.1 如何在整个OS中,通过文件名找到目标文件

我们已知的是目标文件的文件名和他的路径,所以,当我们查找到一个文件的时候,我们都通过路径去逆向的查找,在目录xzy中查找file-operating目录的inode编号,但是此时目录xzy的inode编号未知,所以在home目录查找xzy目录的编号,最终到达根目录的时候(根目录的inode编号是已知的),最后回溯一下,这样就可以得到目标文件的inode了


5.4 分区

你看这就是,我电脑下的两大分区,C盘和D盘

df -h 查看Linux系统下的分区


5.4.1 格式化

向我们对磁盘的操作中就有格式化这种操作,其实上就是清空磁盘中的内容,为磁盘装入全新的文件管理系统。 (每个不同的分区可以装不同的EXT文件系统)

5.4.2 分区进行"挂载"
  1. 前提:一个写入文件系统的分区,要能被Linux使用,必须要把这个具有文件系统的分区进行"挂载"。
  2. 挂载:将一个文件系统所对应的分区,挂载到指定的目录下。使得用户可以通过访问指定的目录,实现访问分区下的目录或文件。

通过解析文件路径(字符串前缀匹配),可以确定哪个目录是文件路径的一部分,从而推断出文件存储在哪个分区上。

挂载的本质:将存储设备上的文件系统,与文件系统(Super Block)中的某个目录(挂载点,dentry)建立关联关系,使得用户可以通过访问挂载点目录来间接访问文件系统上的所有数据。

在这个过程中,Super Block提供了文件系统的全局信息,dentry通过目录下缓存机制来加速文件名的查找,它提供了文件名到inode的快速映射,使得用户可以通过文件名快速访问文件数据。

在这里我就简单的将挂载认为是,为了让分区也能得以区分,把他们放在不同的目录下。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java8中的函数式接口详解(Supplier、Consumer、Predicate、Function)
函数式接口:有且只有一个抽象方法的接口,称之为函数式接口 @FunctionalInterface注解作用:可以检测接口是否是一个函数式接口 是:编译成功 否:编译失败(接口中没有抽象方法或者抽象方法的个数多于1个)
共饮一杯无
2022/11/28
3910
【小家java】java8新特性之---函数式接口(Supplier、Consumer、Predicate、Function、UnaryOperator,通往高阶设计的好工具)
首先,它还是一个接口,所以必须满足接口最基本的定义。但它是一个特殊的接口:SAM类型的接口(Single Abstract Method)。可以在调用时,使用一个lambda表达式作为参数。 定义要求:
YourBatman
2019/09/03
1K0
【小家java】java8新特性之---函数式接口(Supplier、Consumer、Predicate、Function、UnaryOperator,通往高阶设计的好工具)
函数式接口Consumer、BiConsumer、Supplier、Predicate、Function、BiFunction
Java Consumer接口来自Java 8中引入的 java.util.function包。Consumer是一个功能接口,用来作为lambda表达式或方法引用的任务目标(传递一个参数执行指定的方法)。
BUG弄潮儿
2025/01/12
1130
函数式接口Consumer、BiConsumer、Supplier、Predicate、Function、BiFunction
JDK8中的函数式接口功能分析与demo
JDK 8最鲜明的特性就是加入了lambda表达式,该特性最大的不同就是将原有的匿名内部类以语法糖的形式作为入参进入方法,所以Lambda表达式必须兼容函数式接口
关忆北.
2021/12/07
2430
JDK8中的函数式接口功能分析与demo
一篇文章让你搞懂Java8新特性
Java8 现在已经是标配了,但是相信很多小伙伴并没有系统的去了解总结相关知识点。接下来我为大家带来基本的总结。文章后面有总结笔记可以领取哦!期待您的关注。
@派大星
2023/06/28
1620
一篇文章让你搞懂Java8新特性
一文涵盖Lambda,Stream,响应式编程,从此爱上高效率编程
本文结构为 先是一个例子,带你快速体验,之后再去深究里面的方法。以及一些底层原理是如何实现的。从如何用,到如何用好,如何用精。学习操作,学习思维。
用户10143704
2024/04/12
940
【Java8新特性】04 详解Lambda表达式中Predicate Function Consumer Supplier函数式接口
函数式接口的抽象方法的签名称为函数描述符,通过函数描述符可以很好得到Lambda表达式的签名。
爱笑的架构师
2020/09/24
1.5K0
Java 8新特性
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比较串行的流,并行的流可以很大程度上提高程序的执行效率。
用户9615083
2022/12/25
1.4K0
Java 8新特性
java函数式编程Function(java函数式编程实战)
JAVA版本最新的目前已经发布到11了,但目前市面上大多数公司依然在使用Java7之前版本的语法,然而这些编程模式已经渐渐的跟不上新时代的技术了。比如时下潮流前沿spring framework5中的响应式编程就是使用到了函数式编程的风格。
全栈程序员站长
2022/08/02
2.3K0
java函数式编程Function(java函数式编程实战)
Java的函数式接口以及Lambda表达式
在java中,大家肯定使用过lambda表达式吧,这是适用于函数式接口的一种便捷写法。
半月无霜
2023/03/03
4820
Java的函数式接口以及Lambda表达式
一次性实战java8 新特性(全)—— Lambda、Optional、stream、DateTime
本篇博客你将学到: 1.Lambda表达式 2.Optional类,告别空指针异常 3.Stream流式处理 4.时间处理LocalDate、LocalTime、LocalDateTime、ZonedDateTime、Clock、Duration 5.重复注解 6.扩展注释 7.更好的类型推荐机制 8.参数名字保存在字节码中 9.异步调用 CompletableFuture
源码之路
2020/09/03
2.6K0
JDK15就要来了,你却还不知道JDK8的新特性!
现在 Oracle 官方每隔半年就会出一个 JDK 新版本。按时间来算的话,这个月就要出 JDK15 了。然而,大部分公司还是在使用 JDK7 和 8 。
烟雨星空
2020/09/08
9180
JavaSE:第十六章:java8新特性
##java8内容 1.Lambda表达式 ★ 2.函数式接口 ★ 3.方法引用 ★ 4.构造器引用|数组引用 ★ 5.StreamAPI ★ 6.接口中可以定义默认方法和静态方法 ★ 7.Optional类的引入:为了减少空指针异常【了解】 8.新日期API【了解】 9.重复注解【了解】 10.Nashone引擎的使用:在jvm上运行js【后面课程】
Java廖志伟
2022/08/01
6250
JAVA8之Lambda
java8最大的特性就是引入Lambda表达式,即函数式编程,可以将行为进行传递。总结就是:使用不可变值与函数,函数对不可变值进行处理,映射成另一个值。
用户4283147
2022/10/08
4640
JAVA8之Lambda
Java8函数式编程
最近使用lambda表达式,感觉使用起来非常舒服,箭头函数极大增强了代码的表达能力。于是决心花点时间深入地去研究一下java8的函数式。
全栈程序员站长
2022/07/21
6600
Java8函数式编程
java8新特性
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
suveng
2019/09/18
1.6K0
java8新特性
感受 Java Lambda 之美,推荐收藏,需要时查阅
来源:juejin.im/post/5ce66801e51d455d850d3a4a
芋道源码
2019/11/18
6920
马上Java14要来了,你还不知道Java8的新特性?
Lambda表达式, 也可以称为闭包,它是Java8这个版本最重要的新特性.Lambda允许把函数作为一个方法的参数, 可以使代码变得更加简洁.
故里
2020/11/25
7250
马上Java14要来了,你还不知道Java8的新特性?
Java8新特性详解
Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。
Jensen_97
2023/07/20
2.3K0
Java8新特性详解
聊聊工作中常用的Lambda表达式
日常开发中,我们很多时候需要用到Java 8的Lambda表达式,它允许把函数作为一个方法的参数,让我们的代码更优雅、更简洁。所以整理了一波工作中,我常用的,有哪些Lambda表达式。看完一定会有帮助的。
捡田螺的小男孩
2022/12/29
4970
推荐阅读
相关推荐
Java8中的函数式接口详解(Supplier、Consumer、Predicate、Function)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验