操作系统的主要几大管理系统,如进程管理调度系统、内存管理系统、文件系统。在我们平时使用操作系统的过程中,我们接触最多的就是文件系统。因为我们平时无论工作还是生活,我们都要编辑文件 创建文件 来记录具体的工作或事情。下面咱们就说一下文件系统,我们还是从外部使用与内部实现两部分来分开讲。
我们知道我们操作系统内核的外面也就是用户空间下,我们是通过系统调用来使用操作系统提供的功能的,如读取数据包 创建文件等等。那下面我们简单的介绍一下关于文件和目录的系统调用,无论是我们平时使用某类高级语言的函数还是使用shell命令,它们只是封装了这些系统调用来完成功能,所以我们要知道或了解这些系统调用。
文件系统调用 |
|
Fd=create(fileName,mode); |
创建文件系统调用(文件名,权限状态位) |
Fd=open(filename,how); |
打开文件 (文件名,模式(读or写)) |
Close(fd) |
关闭一个文件,意味着对一个文件的操作全部结束 |
N=read(fd,buffers,nbytes) |
读取文件(文件句柄,缓存区,读取的字节大小) |
N=write(fd,buffer,nbytes) |
把数据从缓冲区写入文件(文件句柄,缓冲区,要写入的字节数) |
Position=lseek(fd,offset,whence); |
移动文件指针 |
S=stat(name,&buf) |
获取文件状态信息 |
S=fstat(fd,&bug); |
获取文件状态信息 |
关于目录的系统调用 |
|
S=mkdir(path,mode) |
创建目录(目录路径,权限) |
S=rmdir(path) |
删除目录 |
S=link(oldPath,newPaht) |
创建指向已有文件的链接 |
S=unlink(path); |
删除已有链接 |
S=chdir(path) |
改变工作目录 |
Dir=opendir(path); |
打开目录 |
S=closedir(dir) |
关闭目录 |
dirInfo=readdir(path); |
读取目录项 |
下面我们以linux下ext2文件系统来说一下文件系统的内部实现。
我们首先看一下磁盘的分区示意图.
引导区(启动时读取哪个分区上的操作系统) |
分区表(记录各个分区的位置) |
分区一 |
分区2 |
分区3 |
再看一下每个分区下的数据块
超级块(记录了文件系统的类型,包含的i节点的个数、磁盘块数、以及空闲块链表的其实位置) |
组描述符(存放了空闲块位图以及i节点位图的位置、目录的个数) |
块位图用来记录空闲块的位置 |
I节点位图用来记录空闲i节点 |
I节点存储区 |
数据存储区 |
因为文件系统要知道所有文件的属性信息,比如作者 保护状态 大小 类型,还要知道文件数据在磁盘上的实际存储位置,所以还要记录一个文件所占用的磁盘块。无论是采用链表或者位图来存储一个硬盘上的文件和目录信息,都是要耗费不少的磁盘空间和内存空间(因为在文件修改或创建时是要根据记录来分配空间的),磁盘越大,文件或目录项或空闲块就越多。为了解决这个问题,这些操作系统的设计者就想出了这个i节点的注意,并且很好的在文件系统上实现和应用了。这样在内存中就不必存储所有文件的位置信息了,需要打开哪些文件就将那些文件的i节点存储到内存中即可,我们平时用到打开文件的函数,也就是将文件的i节点信息装入内存。Stat等获取文件信息的函数或系统调用其实也是读取i节点返回的结果。
每个节点都有一个节点号,无论目录还是文件都有一个单独的节点,都是一个单独的小文件,这里面记录了文件类型,是文件还是目录还是可执行文件,还记录了一些属性信息 如大小 作者修改时间等。每一个文件或目录都有一个节点,所以当我们要打开或定位到一个文件时,我们首先要找到第一个目录,在linux下每个目录下都有.和..,.的意思是当前目录,这个里面记录了当前目录的节点号,..的意思是上一级目录,记录了上一级的目录的节点号,。
所以无论是我们采用绝对路径还是相对路径,我们都要一级一级的找到目录的节点号,然后读取i节点信息,这个i节点如果是目录里面就会存有这个目录下的目录名称或文件名称以及对应的i节点号,得到i节点号读取i节点然后继续寻找目标文件,直到最后找到目标文件的i节点号,读取节点信息里面的磁盘块位置,获取文件的内容。
操作系统根据文件中空间块位图以及i节点位图来分配和回收文件的创建和消除的存储分配。
为了防止由于系统崩溃或电源突然中断导致正在进行的文件操作中断所造成的数据丢失,ext2文件系统就必须在每个数据块创建或修改后即刻写入磁盘。磁盘的寻道操作对于cpu来讲是如此的之长,为了提高性能,所以写操作数据被缓存,写操作被延迟。但这样也带来了数据丢失的风险,假如数据还没来得及写入磁盘,电源突然中断,数据将会丢失。为了解决这个问题,所以有了ext3文件系统。
Ext3其实只是ext2文件系统加上了一个日志维护功能,增强了文件系统的健壮性。每一个磁盘操作都会将其具体的操作位置以及数据记录到日志里。当发生系统崩溃或电源中断时,再次启动时,文件系统会比对日志与磁盘是否一致,不一致则根据日志来完善操作。这也是当系统崩溃后,我们再次启东时,硬盘要自检的原因。
网络功能在linux中占据着不可动摇的地位,当然文件系统也要强大到支持非本地文件系统。其实网络文件系统就是在linux操作系统下,将远程机器上的目录挂载到本地的文件系统上,首先远程机器会检查客户机器的挂载请求以及权限验证,通过则将自己的文件系统类型以及被挂载目录的i节点信息组成的一个唯一标识放到本地。当本地有对此文件操作时,文件系统就会检查当前被挂载的目录是本地文件系统还是网络文件系统。如果是网络文件系统,则通过网络文件系统协议发送读取文件或者打开文件的请求,包含文件名以及读取的位置或要写入的数据或位置,然后远程机器返回相应。
其实在上面说网络文件系统时,我们就已经提到了。那个检查要操作的文件是本地还是远程的文件系统就是虚拟文件系统,我们所有的文件系统调用都应用到这个系统里,这个文件系统包含本地文件系统处理办法和远程文件处理办法,比如当检测是本地文件,则使用本地文件系统无论是ext2还是ext3进行操作,如果是网络文件,则采用当前文件的网络文件系统协议进行通信完成操作,这样我们就不必去关心文件是在本地还是在远程,是在内存还是在磁盘上。
文件系统的工作就是帮我们完成文件在磁盘上的存储功能,而且是高效的、节约的。最后还是那句话,无论是什么技术,都是一步一步的完善的,刚开始的文件系统就是在磁盘上连续分配,后来一步一步的改良,到达现在的局面。现在我们有了更加健壮的文件系统 有了更加快速的内存文件系统 还有更方便的网络文件系统。还有另一个更重要的就是磁盘阵列来分散读写请求以及实时备份数据。