建立网站流程,怎么创建一个网站,网页制作特效代码大全,兰陵成都设计公司先前的博客我写了关于缓冲区的理解#xff0c;顺便提及了在内存的文件是怎样管理的#xff0c;本文就来描述在磁盘上的文件是怎么样。但要先了解了解磁盘。 在笔记本上机械磁盘被固态硬盘代替#xff0c;因为固态硬盘更快#xff0c;而且方便携带#xff0c;机械硬盘若是受… 先前的博客我写了关于缓冲区的理解顺便提及了在内存的文件是怎样管理的本文就来描述在磁盘上的文件是怎么样。但要先了解了解磁盘。 在笔记本上机械磁盘被固态硬盘代替因为固态硬盘更快而且方便携带机械硬盘若是受到外部碰撞非常容易损坏但在大型服务器的存储中机械磁盘几乎不会被代替因为要控制成本效率虽然会慢但是这里面存的一般是用户比较旧的数据例如一年前的聊天记录你几乎不会再看了所以没必要追求IO的速度这点挺巧妙的。 但如果是你立刻可能会看到的例如刚发的朋友圈那就会放在大量固态硬盘的存储集群上既保证效率又保证成本。
一 认识硬件---磁盘 计算机中唯一有机械运动的设备存储时会要有机械运动辅助因为数据都在磁盘的一个一个的磁性区域要寻找访问这些区域是靠机械运动所以注定比固态硬盘这些电传输慢因为电传输的速度貌似是接近光速的。 摔了容易损坏因为磁头和盘面很接近若是在在打开状态下摔了电脑磁头会和高速移动的盘面接触直接损坏硬件所以机械磁盘退出便携式笔记本是必然。同理磁盘内也不能有灰尘否则在高速运动下会刮花盘面逐渐造成数据缺失。 学了这么久的计算机我们很早前就听说一个常识那就是计算机内只认识0和1这是因为计算机内的各个硬件是靠电路链接比较容易使电路呈现两种状态通电断电假如我们想让计算机再认识一个2那就要能让电路呈现第三种状态只能通过电流值例如某个电流值以下是1以上是2但是电流是会出现波动的如果在传输数据时一旦电压不稳你本来想传2结果变成了1影响是什么呢我如果让发电站故障一下我能影响全世界的运算结果。科学家们解决不了电流稳定的问题那就只能让电路只表示两种状态由此计算机内一切的数据都是二进制。总而言之所以硬盘接收到的也只能是0和1但是磁盘不是靠电存的但是一定要有两种状态能分别表示0,1。如下初识磁盘的储存过程。 首先磁盘收到来自内存的电信号接收来自内存的数据以及存储位置磁头拿到位置后进行定位定位后磁盘如何存储数据储存规则: 可以认为磁盘就是一个个小的有磁性的区域这个磁性区域有N级和S级规定N级在上S级在下这个磁性区域表示1相反表示0如果我们通过某种手段把这个磁性区域的磁级逆置了就相当于往该区域写了个1或0。 那读数据估计就是和磁头有关了磁头判断该区域的上方是N级还是S级从而判断这个磁性区域是1还是0。 而要销毁这个磁铁的磁力只能烧毁不能直接删除文件达到删除磁盘上的数据的目的吗?不行因为我们删除一个文件不是删数据而是更改一些属性数据。在解释文件系统和文件系统拓展时会提及到时候我们就能理解为什么删除一个文件很快。而下载一个文件则很慢。
二 对磁盘的抽象理解 先前已经大致了解了磁盘的大体结构工作原理可是磁盘上有那么多的磁性区域我存储和读写数据如何寻址? 设计上规定磁盘的基本单位是一个扇区下面是一块盘面的扇区图。一个扇区大小是512字节一个磁道内会有多个扇区一个完整的空心圆弧就是一个磁道这样多个磁道就变成了一个完整盘面。 一个磁盘会有多个盘面和对应的磁头。 所以如何寻址就变成了如何定位扇区的问题先来看看机械运动如何确定扇区:一开始就要先确定盘面确定让哪个磁头运动随后磁头沿着半径运动就是在确定磁道沿着圆弧方向就是在确定扇区。这种确定磁头确定磁道最后确定扇区的定位扇区方式称为CHS(英文首字母)访问磁盘的消耗:磁头确定磁道以及盘面自转帮磁头确定扇区所以说访问磁盘的效率取决于机械运动读取数据的消耗似乎比找到数据的消耗还小所以为了提高效率一定要把数据尽量放一起就不用进行太多的机械运动。 噢我知道了机械运动如何确定扇区但是我告诉了磁盘什么数据让磁盘知道我要访问哪个扇区呢要解释得再来看看对磁盘的抽象理解。 我们已经知道磁盘实质上就是一个个的扇区先把所有的扇区按顺序像数组一样整齐排列。此时我们把磁盘抽象为一个线性的大数组那每个扇区天然就有个下标。这些下标就是扇区编号。 我们认为各个磁道上的扇区数量是一样的虽然外侧的圆圈更大但为了方便理解我们就认为外侧的扇区比较稀疏内侧的扇区比较密集所以扇区数量一样。而扇区编号就是书本上提到的LBA地址所以设计者肯定是让磁盘能根据磁道号找到对应的磁道根据扇区编号找到扇区从而读取数据。转换如下。 为什么还要弄一个LBA地址出来呢你直接用个CHS地址不行吗有一种解释是LBA让os不用关心磁盘结构磁盘内部有一个控制器它负责将LBA地址转为CHS地址让磁头去访问但对于os来说自己只使用LBA地址就不用关心地址转换更不用关心磁盘结构是什么反正只要拿着这个LBA地址磁盘会把数据给我其它的我不关心。(老实说这里的解释我还是有点模糊毕竟没经历太多) 显然os不需要定义一个这么大的数组只需要知道一个扇区多大然后磁盘总容量多少这样就知道了总扇区数除以盘面甚至可知每个盘面的扇区数再由磁道数得知每个磁道上平均的扇区数当然本文是在每个磁道扇区数一致的情况下讨论的如果不一致那肯定要多记录一些参数。 磁盘也有寄存器用来快速获取cpu的指令先告诉磁盘写还是读再告诉磁盘读写的地址以前是通过数据寄存器一点点传因为最后要等寄存器数据存到了磁盘的位置才可以继续从内存读到寄存器现在来理解就是计算机内还有个DMA芯片负责IO磁盘可以和DMA芯片合作直接读内存数据导入到磁盘中间不经数据寄存器但速度快不了多少因为时间消耗主要是写到磁盘。 三 文件系统 磁盘划分 我们现在只知道怎么写但是不知道能不能写因为不知道这个扇区有没有被占用所以需要文件系统来管理。首先来看看磁盘空间是如何被管理的——分区管理。 可是这实际上是一个个的扇区啊那我怎么表示D盘有哪些扇区很简单用start记录起始扇区下标end记录区域内最后一个扇区下标然后每个分区分别初始化两个下标就可以实现分区了而给定一个分区的容量和扇区大小就知道这个区域内有多少扇区了然后先前分区的end下标1就是下一个分区的起始扇区下标然后加上扇区数量就是下一个分区的end扇区下标。 为什么要分区呢?首先是安全由于分区了每个区域都会有自己的管理系统这样一个系统被破坏就不会影响其它区域的系统查资料还说因为以前的病毒经常会破坏c盘所以只能分区让c盘承受伤害。还有个原因是好管理下面再细说。 如果我们的文件系统能管理200个G那就可以把这套系统复制到其它分区假如大小为150个G就能管理150个G因为200个G内文件的各种属性可以被管理那150G的文件属性也没问题。 分区后又分成一个个Block group(分组)。每个group block大小可能为10g。Boot Block存的是os开机后需要的管理信息让在内存的os知道磁盘的分区情况等有点抽象简单理解就是存了os可以不理会。 为什么要再划分呢?首先文件系统肯定要加载到内存因为文件系统本质上是os的一部分因为磁盘也是硬件当然要被os管理如果你不分区分组要加载到内存的文件系统是会占用许多内存的分区分组后我们进程使用了哪个文件将文件所在分区的文件系统加载到内存即可能省一点是一点啦。还有就是和分区原因有个公共点那就是方便管理如何理解方便管理呢?会在文件系统拓展解释如何文件做增删改查时顺便抛出解释。
BlockGroup内部介绍 终于要开始讲文件系统了。
1 super block(超级块) 首先规定着各分组中的文件系统内的GDTData Blocks等信息的占用的空间分布顺序剩余空间还有整个分区的基本使用情况也就是下图的内容。 不会存在每个组上只会存两三份一方面是为了保险起见多存几份免得丢失后os不知道磁盘的当前分区的各个分组的边界这样就无法将inode编号转为具体扇区编号下面介绍还有很多操作需要超级块内的信息如果没了那些操作都做不了了整个分区就完蛋了还有一方面是不能存太多份可以理解为每次创建文件后超级块内某些信息要修改存太多份超级块维护成本太高。
2 Group Descriptor Table(GDT) 块组描述符。 虽然下面Block Bitmap和inode Bitmap已经描述了inode Table和Data Blocks的使用情况但是若要统计还剩下多少个或者说剩余有效空间大小就得遍历Block Bitmap和inode Bitmap这比较浪费时间所以就用Group Descriptor Table保存了使用了一个GDT内部的记录inode数量的变量就--想知道数据块空间剩余用block剩余数量*一个块大小即可。
3 InodeTable 一个文件的属性会被分配128字节所以一个扇区会存在多个文件的属性如何区分就是用属性中的inode值。 那inode值哪来谁分配的首先磁盘所有分区的inode范围是被规定好的那由一个文件一个inode编号得出能创建的文件是有限的inode给各个组的分配也是规定好的所以当要创建文件时会先看在哪个分区创建然后遍历分区内的小组先在GDT看看当前组还有没有inode剩余没有就去下个组然后遍历inode Bitmap有空位就用这个然后加上当前组的起始inode(超级块存着)就是分配给文件的inode编号了。 inode表内部存多个文件的属性内部结构应该是类似哈希表的。如何查文件inode编号如下图。 这就是文件属性和内容分开存的含义而且文件属性一定存着文件内容占了哪些块还有文件属性内没有文件名那我们平时找文件都是用文件名如何和inode对应简单理解就是目录文件的内容中会保存自己目录下的文件名和inode对应关系没错目录也是个文件。那inode如何找到自己的内容块在inode内有一个数组这个数组内存的就是内容块编号。 0下标到11下标中存块号这些块号对应的块存文件内容后面存的块号对应的块存的不是文件内容而是专门存块号。12下标和13下标对应的块专门存块号又称二级索引大约能存2048个块号能存内容8mb。但是不意味着文件最大只有8mb。 14号数组内的类似三级索引这个对应的块专门用来存二级索引的如下图10号块内存块号这些块号指向的块存的还是块号最后指向的才是内容这样就能映射一百万个块差不多4G了。 4 DataBlocks 存文件内容是以块为单位的大小是4kb也就是说哪怕你文件只有一个字节也要给你分配4kb原因虽然磁盘的基本单位是扇区但是os在访问时却是以4kb为单位一次刚好访问一个数据块的文件内容就是为了减少io次数提高效率而且这最多只会多读一个块但磁头运动次数大大减少了效率还是会提高的。 所有文件内容都在这个DataBlocks内这该如何查找呢 从前面超级块的介绍得出显然我们能从中知道一个分组的起始扇区编号以及分组内各区域的起始扇区编号。而且一开始整个空间的大小各个区域空间也是超级块规定好的显然Data Blocks内的块数也是可知的所以每个数据块天然就有了自己的编号。编号作用知道Data Blocks的起始扇区编号和数据块大小只要再知道数据块编号那任意数据块的扇区编号也就知道了就能让磁盘找到了。所以文件属性只要存了数据块编号就能转为数据块的扇区编号然后找到文件内容。当然还可以用来和bitmap上面的比特位进行映射如下。 由上得inode和数据块数量是规定好的所以会出现inode分配完了但数据块还有inode还有但是数据块没了没办法解决。
5 Block Bitmap和inode Bitmap Block Bitmap和inode Bitmap分别标记inode和数据块是否被占用比特位的位置分别和inode编号和block编号映射起来比特位上的内容表示inode,block是否被使用由此得我们删除文件时只要将对应这个位图上的比特位清0然后在超级块以及GDT内修改inode和block剩余就可以了所以删除一个文件的速度比较快。什么!你说为什么不删内容没必要直接让下个使用该空间的文件覆盖写就可以了就算没覆盖完显示文件内容时也不会影响因为文件有大小的嘛你别把垃圾数据算成文件大小显示文件内容就按文件大小来显示即可。
周边问题解释1 inode编号如何与bitmap下标对应? 首先整个分区分组的inode的数量起始inode数值是确定的组内的inode范围也就知道了(超级块存着)也就可以提前设置位图来管理所有的inode的。
周边问题解释2 规定:inode值是在一个区内是唯一的但在其它区可能会重复因为我们可以判断文件在哪个区所以没必要让不同区的inode值不一样诶你是怎么判断文件所在区的呢?简单理解就是分区的文件系统会被加载到内存中os通过管理这个文件系统来管理整个分区而这个文件系统会被加载到某个目录下这个动作称为挂载我们创建文件时也会有个路径或许这个路径就是属于某个分区的文件系统管理在这下面创建的都属于这个分区所以说我们根据路径可以判断分区。 而为了让一个分区内的文件具有唯一的标识符所以组和组之间的inode值范围是不一样的保证分配时不会出现一个inode标识两个文件inode怎么判断属于哪个组呢很简单前面说了每个组的inode范围是知道的所以用inode编号可以判断在哪个组而且和block编号一样都能被转为具体的扇区编号此时inode值不仅在一个分区内用来标识文件还可以用来判断所在分组减少检索范围。
周边问题解释3 由此得而且文件属性和文件内容应该是要在一个块组内的因为各个分组的数据块编号是会重合的仅仅凭借文件属性内存的数据块号是无法区分在哪个分组的。
四 文件系统拓展 当我们大致了解了文件系统内的各个字段接下来就开始用对这些字段的了解来解释一些问题。但还需要一点点知识准备。
1 理解目录 我们一般访问文件都是只用文件名例如cat test.c找文件不是用inode吗系统如何将文件名转为inode呢?靠目录。目录也是文件所以有自己的属性里面有权限信息而内容存的是目录下的文件名和inode的映射关系。 好目录也是个文件要访问文件内容就要先找到文件找文件又要inode那我怎么获取目录的inode从上级目录中找因为目录名和自己的inode就保存在上级目录文件的内容中噢所以找一个文件要带路径。 诶不对啊到时候我们要一直找到根目录的难道说根目录的inode操作系统知道?我觉得差不多可以这样理解所以找到一个文件必须要有路径例如/usr/bin/test此时就是现在根目录下找到usr目录的inode然后再找到bin目录的inode然后在bin文件内容找到test文件的inode最后找到文件属性和内容。 那用相对路径如何查找有相对路径的前提是先找到当前目录然后再解析相对路径找到分叉点再根据路径继续找文件名和indoe的映射关系由上得这样太慢了所以目录dentry缓存会记录历史上常用的目录的inode。 目录常识底层解释 所以说目录下不能有同名文件因为文件名和inode是kv映射的文件名就是key。 创建文件要把文件名和inode写到目录的数据块中没有w权限就不能创建文件肯定是先拿到目录文件内的权限信息了判断后不让往数据块写。 同理没有r权限无法ls查看目录下的文件因为此时不让读目录文件的数据块了也就拿不到文件的文件名和inode更拿不到文件的属性。 没有x权限也无法cd进入该目录去查看目录文件属性发现目录的权限没有x也就不让cd了。 2 对磁盘格式化后做了什么 按我们现在的理解就是会把文件系统上的bitmap那些字段都清空还有就是格式化可能会用其它的文件系统来格式化也就是说下图的文件系统字段重新写入因为每个文件系统对分区分组的要求可能不一样所以一旦格式化要改所有的文件系统信息。 3 新建文件要做什么 先用路径判断分区(文件系统周边问题解释中曾提及)然后去GDT看组内有无剩余的inode然后去inode Bitmap里看哪个比特位是空的最后要加上当前组的inode起始编号这就是分配inode的过程。还要分配数据块也是如此先去GDT看看有无剩余再去数据块位图找空数据块的编号然后把块号填入到属性中随后就直接跳转到对应数据块写数据了。
4 那如何查找一个文件 现在我们就知道cat test.c是由路径找到目录文件内容(虽然我们没有明显写路径但是环境变量提供了你试试查看其它目录下的文件就一定要带路径)再提供对应文件的inode值然后用inode值确认分组在分组内的inode Table找到文件属性文件属性内有数据块编号前面已经提过如何用数据块编号跳转到对应扇区。
5 删除文件要做什么 删除一个文件也就是删属性和内容所以要先查找文件(参考前面查找文件)。至于删除文件的操作先前在5 Block Bitmap和inode Bitmap介绍曾提及过也就是改一改位图上的比特位。
6 修改一个文件做什么 修改一个文件本质就是先查找文件属性和内容然后再修改所以具体操作和查找文件相同。 由此得对文件做增删改查本质上是要对这些位图做增删查改所以当然是位图越小越好不然分配inode遍历位图比较费时间所以要分区分组把管理区域变小才能快速遍历位图实现增删改查。
五 软硬链接
1 建立软链接 1 ln -s d1(目录) d2(目录) 此时会创建一个软链接名字为d1是和d1链接。目录d1,d2是已经创建的目录也是文件也可以被链接。 会认为是要在d2下创建一个软链接和d1链接但又没写文件名所以会默认在d2目录下面创建一个d1文件然后作为d1目录的软链接但是我们写的目标文件和源文件都没带路径这个时候出来的软链接会有问题。而且我们可以看到的是此时这个软链接名为d1然后inode为786508和d1的inode值786460不同这说明软链接文件和被链接的文件是两个不同的文件。 而如果链接对象是一个已经存在的文件然后后面又不写路径和文件名则会认为要在当前路径下创建一个软链接名为test.c会引发引发命名冲突因为软链接其实还是文件文件名和inode要存到目录文件的内容中所以不能重复。 老老实实带完整路径再测试一下。此时的颜色就正常了。 也可以正常使用。先进入d1目录查看目录下的文件再cd d2目录下的软链接ls查看出的文件信息是一样的。注意:我此时是用一个软链接和一个目录进行连接才可以对软链接使用cd命令估计是cd内部做了判断会去获取软链接内存的路径看看指向文件是否是目录是目录的话cd test就被转换成cd /home/hay/d1。 不带路径是默认在当前目录下创建软链接前面不正常应该算是写了路径又没写完整。 如果目标文件d4不存在会创建一个目标文件d4去链接我本来想测试目录去链接目录现在看来没有这种情况或许是ln命令规定创建一个链接文件作为其它目录文件普通文件的软链接而不是目录以及普通文件做别人的软链接这一点我也是运气好才理解清楚。 2 软链接的本质和应用 软链接的本质:在文件内容中存了指向文件的路径就像是windows下的快捷方式为什么不能存inode因为要用路径判断分区和获取inode再用inode判断分组找文件所以不如直接给路径。 软链接使用场景:可以简化使用难度有时候我们要在当前目录下运行一个可执行文件test但是其路径太深每次运行都要带路径。 我们就可以用软链接简化直接./test就可以了值得说明的是既然软链接内存的是被链接文件的路径如果我们修改了这个文件的路径此时软链接会失效。 如果此时用硬链接呢? 也可以跑那我就有点疑惑了那用硬链接和用软链接好像没区别啊?有没有种情况硬链接无法使用只能软链接上当然有这就要结合软硬链接的本质来说了硬链接如何查看文件内容呢?先通过自身的路径判断分区然后解析路径获得inode最终找到inode问题就出在用自身路径判断分区上这就规定了硬链接必须和被链接文件在同一个分区而软链接则不需要。 3 建立硬链接 ln 源文件 路径硬链接名。 对于硬链接的使用有几点要说明1 首先被链接文件绝对不能是目录bash会检查不是权限的问题而是直接的硬性要求直接杜绝这种情况因为容易造成环路问题。 此时如果执行find / -name test.c如果找到了这个硬链接那就会跳转到root继续找一直死循环。让find禁止对硬链接搜索治标不治本如果很多函数都有这个问题难道一个个禁止对硬链接操作吗所以就直接禁止对目录进行硬链接了。 2 如果是对test.c文件做硬链接此时d2是个目录不会认为是d2这个目录做test.c的硬链接而是认为你没写目标文件名然后在d2目录下创建一个test.c的目标文件作为硬链接。和软链接情况类似。
4 软链接的本质和应用 如下图硬链接的本质是在特定目录的文件内容上增加了文件名和inode的映射关系是在哪个目录文件的内容增加呢? 就是硬链接名前面的路径指定的目录如果不写就是在当前目录下增加。 软连接硬链接的第一个区别就出来了前者为不同文件后者为同一文件——由被链接文件的inode的值和软硬链接文件的inode比较可得再次证明文件属性内无文件名如果保存了那从文件属性内取得的文件名应该是一样的。还有个小细节我们会发现file.txt的属性有个数值从1变成了2这个数称为硬链接数是什么呢我们可以测试一下我们发现rm删除了test.txt后这个数-1了。 其实就是inode内的引用计数也就是用来记录有多少个文件名和inode数值对应(注意由于文件属性是struct inode所以有时候称inode是指文件属性而struct inode内还有个变量叫inode number所以有时候称inode是指文件标识符inode数)那为什么inode内会有一个引用计数呢可能就是为了服务于硬链接免得rm文件直接就删了而其它文件名还指向这个文件呢。 硬链接场景.和..就是一种硬链接.和当前目录链接..和上级目录链接/的引用计数由.和子目录的..和自己构成那为何不用软连接呢软链接也可以和目录链接啊我想可能是因为软链接是单独的文件属性是和链接文件不一样的对就是因为属性或者说是权限属性.和..作为硬链接的话权限信息是不变的而作为软链接的话权限会发生改变就可能使得我本来有权限访问目录却没有权限用你这个软链接所以就直接用硬链接。 诶不对啊你前面不是说不能对目录进行硬链接吗那.和..不就是对目录进行链接吗不用担心前面的环路问题是因为搜索时会对硬链接也进行搜索os规定.和..不被搜索就不会出问题毕竟os是规则的制定者有大把的方式绕开规则我们就不行了当然.和..的作用也很大使得linux产生了相对路径的概念方便我们作路径跳转。 这篇博客中的软硬链接用到了不少文件系统的内容为了完整性只好放一起了第一次写这么长的博客。