硬盘分区后,如果想要实现对文件的快速存取以及访问,还要依赖文件系统,需要在分区上面创建文件系统。
文件系统是一个软件,它存储在磁盘的某个位置上,但是文件系统本身并不在这个分区上,文件系统的数据存在这个分区上。
文件系统是一个软件,此处以ext文件系统为例,ext文件系统在存放文件数据时,会把文件的元数据和数据分开存放,它把分区分成两个部分,一部分放数据文件(示意图-1中黄色区域),另一部分放这些数据文件的元数据(示意图-1中橘色区域),而存放文件的区域又被分区一个一个逻辑存储单元,称为一个磁盘块block,块是逻辑概念不是物理概念。
而每个数据文件存在哪些块中,从哪个块开始,到哪个块结束,都是存在一条元数据条目中的,所以每个数据文件都会对应一条元数据条目,这个元数据条目被称为inode(index node --索引节点),每一个inode有一个全局唯一的ID(这里的全局指的是某个分区下,某分区下不同文件的inode号不可能相同,不同分区的inode号有可能相同),每个inode中存放了对应文件的inode号,文件类型、属主属组、权限、大小、时间、以及文件数据存储在哪些磁盘块 等信息(元数据中没有当前文件的文件名,当前文件的文件名存放在父目录的数据块中),如果一个文件过大,那么他需要的块就会很多,inode中存储的对应块信息就会很多,但是如果文件很大,成千上万的块信息的存储空间就会很大,它可以利用指针,指向另一个更大的空间,存储这些块信息。
示意图-1
inode存放在inode表(inode table)中,一条inode信息(元数据条目)称作这个inode表中的一个索引节点条目(inode
entrv),一个inode entry中包含有关文件的元数据信息,包括:
文件类型,权限, UID, GID
链接数(指向这个inode的文件个数)
该文件的大小和不同的时间戳
指向磁盘上文件的数据块指针
有关文件的其他数据
示意图-2
图中的直接块指针有12个,每个直接指针都可以直接指向一个块,假设我们在格式化文件系统的时候指定块大小为4k,那么直接块指针指向的块的大小总和为 4k * 12 =
48k , 即 如果一个文件的数据大小不超过48k,那么只使用直接块指针指向的块就能满足数据存储的要求。
但是如果某个文件稍微大一点,文件大小大于4k,‘直接块指针’ 指向的块的大小无法满足存储要求,这时候就会用到‘间接块指针’,‘间接块指针’指向一个数据块,我们暂且称这个被‘间接块指针’指向的块为‘间接块’,‘间接块’中不存放数据,而是存放指针,这些存放在‘间接块’中的指针再指向真正存放数据的块,我们还按照上述假设,每个块4k大小,假设每个指针占用4个字节的空间,那么一个4k的块能存放1024个指针,也就是间接块中能存放1024个指针,这些指针每个再指向一个4k的块,那么所有能指向的块的大小为4k * 1024 = 4M ,也就是说能够存放小于4M大小的文件。
同理,如果文件大于4M,‘间接块指针’能够指向的所有块的大小总和无法满足要求,这时候就会用到 ‘双重间接块指针’ ,‘双重间接块指针’的原理跟‘间接块指针’的原理相同,只是又多间接了一层,‘双重间接块指针’先指向一个‘间接块’,这个间接块里存放了1024个指针,‘间接块’里的每个指针再指向一个‘二重间接块’,因为每个块的大小都是4k,所以每一个‘二重间接块’又能分化出1024个指针,这些来自‘二重间接块’的指针再指向真正存放数据的块。所以,总共算下来,能够存放1024 * 1024 * 4k = 4G 的数据。
三重间接块指针的原理同上,以此类推。
而我们上面提到过,文件的元数据中并不包含这个文件的文件名,那么文件的文件名保存在哪里呢?答案是保存在父目录的数据块中,我们说过目录也是一个文件,是一个特殊的文件,而每个文件都有自己的数据和元数据,目录也有,目录的数据也存在对应块中,假设A目录中有三个文件,分别为b、c、d文件,那么A目录的数据块中存放的数据如下,所以,文件本身的元数据中不包含文件名,而是存在于父目录对应的数据块中。
其实在定位一个文件的时候,就是通过目录块中的数据,一次次迭代查找inode号,最终定位到指定文件的,举个例子:
假如我们想要查看/etc/issue中的数据,那么文件系统会从根目录开始,从inode table中找到根目录的inode条目,通过inode条目中的指针找到根目录存放数据的块,此块中保存了根下的文件或目录的名称以及它们对应的inode号,如bin,sbin、etc等,从根目录块中找到etc目录对应的inode号,再回到inode table中找到etc目录的inode条目,通过etc的inode条目中的指针找到etc目录对应的数据块,再从这个块中找到这个etc目录下issue文件对应的inode号,然后再回到inodetable中,通过issue的inode号找到对应inode条目,通过条目中的指针找到issue文件存放数据的块,读取块中的内容,展示到输出设备中。
同学们会觉得这样来回来去好麻烦,会不会很慢,但是我们在使用时却没感到慢,那是因为inode table会被加载到内存中,元数据会缓存到内存中,所以不会感觉到慢。
在元数据区域中(示意图-1中橘色区域中),还有一个逻辑区域,里面存放的是哪些块是可用的,哪些块是已经被占用的,这个区域叫‘块位图‘(bitmap),在块位图中,每个块对应一个位,标记了这个块是否可用,当我们需要存放数据时,不需要遍历所有的块来判断哪些块可用,而是遍历这个块位图即可。
而因为每个文件的元数据都存放在一个inode中,但是因为长期使用,不断的添加删除文件,存放inode的区域也会出现一些已用的或者空间的inode存储区域,所以,对应inode的存储情况,也会有一个位图,用于遍历哪些inode存储位可用,哪些是已用的。
创建新文件是必须有路径文件
删除文件只是将路径下的信息删除,然后将对应inode和block标记为空闲即可,等待信息数据覆盖
复制文件相当于创建新文件
在一个分区下剪切一个文件非常快,那是因为它只是把路径改了一下,文件没有变,就是说inode没有变
使用df -i 命令可以查看inode使用量的情况 ,如果分区中的inode使用完了,即使分区还有空闲空间,也无法再创建新的文件,因为已经没有inode可以分配给新文件使用了。
而硬盘在实际的使用中,还会将块分为块组,每个块组还有一个全局信息,记录了这个块组的信息。这个全局块叫超级块,而在每个块组中又有块组的块位图及inode位图,然后原理就跟上面描述的原理一样了。
不同的文件系统中,都有类似上述的inode的概念,只是具体实现可能不同。