Linux中的各类事物诸如像文档、目录(MacOSX和Windows系统下称之为文件夹)、键盘、监视器、硬盘、可联通媒体设备、打印机、调制混频器、虚拟终端,还有进程间通讯(IPC)和网路通讯等输入/输出资源都是定义在文件系统空间下的字节流。
一切都可看作是文件,其最明显的用处是对于前面所列举的输入/输出资源,只须要相同的一套Linux工具、实用程序和API。你可以使用同一套api(read,write)和工具(cat,重定向,管线)来处理unix中大多数的资源.
设计一个系统的终极目标常常就是要找到原子操作,一旦锁定了原子操作,设计工作都会显得简单而有序。“文件”作为一个具象概念,其原子操作十分简单,只有读和写,这无疑是一个十分好的模型。通过这个模型,API的设计可以化繁为简,用户可以使用通用的方法去访问任何资源,自有相应的中间件做好对底层的适配。
现代操作系统为解决信息能独立于进程之外被常年储存引入了文件,文件作为进程创建信息的逻辑单元可被多个进程并发使用。在UNIX系统中,操作系统为c盘上的文本与图象、鼠标与鼠标等输入设备及网路交互等I/O操作设计了一组通用API,使她们被处理时均可统一使用字节流形式。换言之,UNIX系统中除进程之外的一切皆是文件,而Linux保持了这一特点。为了易于文件的管理,Linux还引入了目录(有时亦被称为文件夹)这一概念。目录使文件可被分类管理,且目录的引入使Linux的文件系统产生一个层级结构的目录树
在Linux系统中,一切都是文件,理解文件系统,对于学习Linux来说,是一个十分有必要的前提
Linux上的文件系统通常来说就是EXT2或EXT3,但这篇文章并不打算一上来就直接讲它们,而希望结合Linux操作系统并从文件系统构建的基础——硬盘开始,一步步认识Linux的文件系统。
1.机械硬碟的化学储存机制一个硬碟有多张硬碟叠成,不同硬碟有编号每张硬碟上的储存颗粒成环型一圈圈地排布,每一圈称为扇区linux操作系统教程,有编号每条扇区上都有一圈储存颗粒,每512*8(512字节,0.5KB)个储存颗粒作为一个磁道,磁道是硬碟上储存的最小化学单位N个磁道可以组成簇,N取决于不同的文件系统或是文件系统的配置,簇是此文件系统中的最小储存单位所有大盘上的同一扇区构成一个圆锥,称为柱面,柱面是系统分区的最小单位
盘片读写文件的时侯,首先是分区读写的,由inode编号(区内惟一的编号前面介绍)找到对应的扇区和磁道,之后一个柱面一个柱面地进行读写。机械硬碟的读写控制系统是一个令人叹为观止的精密工程(一个大盘上有几亿个储存单位,每位扇区长度不到几十纳米,c盘每分钟上万转),同时关于读写的逻辑也是有众多细节(例如磁道的编号并不是连续的),十分有意思,可以自行搜索文章拓展阅读。
有了硬碟并不意味着LInux可以立即把它拿来储存,还须要组合进Linux的文件体系能够被Linux使用。
2.Linux文件体系
Linux以文件的方式对计算机中的数据和硬件资源进行管理,也就是彻底的一切皆文件,反映在Linux的文件类型上就是:普通文件、目录文件(也就是文件夹)、设备文件、链接文件、管道文件、套接字文件(数据通讯的插口)等等。而这种种类繁杂的文件被Linux使用目录树进行管理,所谓的目录树就是以根目录(/)为主,向上呈现分支状的一种文件结构。不同于纯粹的ext2之类的文件系统,我把它称为文件体系,一切皆文件和文件目录树的资源管理方法一起构成了Linux的文件体系,让Linux操作系统可以便捷使用系统资源。
所以文件系统比文件体系囊括的内容少好多,Linux文件体系主要在于把操作系统相关的东西用文件这个载体实现:文件系统挂载在操作系统上,操作系统整个系统又置于文件系统里。但本文中文件体系的相关内容不是好多,大部份地方都可以用文件系统取代文件体系。
1.Linux中的文件类型:
1.1.普通文件(-)
从Linux的角度来说,类似mp4、pdf、html这样应用层面上的文件类型都属于普通文件
Linux用户可以按照访问权限对普通文件进行查看、更改和删掉
1.2.目录文件(d,directoryfile)
目录文件对于用惯Windows的用户来说不太容易理解,目录也是文件的一种
目录文件包含了各自目录下的文件名和指向那些文件的表针,打开目录事实上就是打开目录文件,只要有访问权限,你就可以随便访问那些目录下的文件(普通文件的执行权限就是目录文件的访问权限),而且只有内核的进程才能更改它们
尽管不能更改,而且我们能否通过vim去查看目录文件的内容
1.3.符号链接(l,symboliclink)
这种类型的文件类似Windows中的快捷方法,是指向另一个文件的间接表针,也就是我们常说的软链接
1.4.块设备文件(b,block)和字符设备文件(c,char)
这种文件通常隐藏在/dev目录下,在进行设备读取和外设交互时会被使用到
例如c盘硬盘就是块设备文件,并口设备则属于字符设备文件
系统中的所有设备要么是块设备文件unix的文件系统,要么是字符设备文件,无一例外
1.5.FIFO(p,pipe)
管线文件主要用于进程间通信。例如使用mkfifo命令可以创建一个FIFO文件,启用一个进程A从FIFO文件里读数据,启动进程B往FIFO里写数据,先进先出,随写随读。
1.6.套接字(s,socket)
用于进程间的网路通讯unix的文件系统,也可以用于本机之间的非网路通讯
这种文件通常隐藏在/var/run目录下,证明着相关进程的存在
Linux的文件是没有所谓的扩充名的,一个Linux文件能不能被执行与它是否可执行的属性有关,只要你的权限中有x,例如[-rwx-r-xr-x]就代表这个文件可以被执行,与文件名没有关系。跟在Windows下能被执行的文件扩充名一般是.com.exe.bat等不同。
不过,可以被执行跟可以执行成功不一样。诸如在root主目彔下的install.log是一个文本文件,更改权限成为-rwxrwxrwx后这个文件才能真的执行成功吗?其实不行,由于它的内容根本就没有可以执行的数据。所以说,这个x代表这个文件具有可执行的能力,而且能不能执行成功,其实就得要看该文件的内容了。
尽管这么,不过我们一直希望能从扩充名来了解该文件是哪些东西,所以通常我们还是会以适当的扩充名来表示该文件是哪些种类的。
所以Linux系统上的文件名真的只是让你了解该文件可能的用途而已,真正的执行与否依然须要权限的规范才行。例如常见的/bin/ls这个显示文件属性的指令要是权限被更改为难以执行,这么ls就弄成不能执行了。这些问题最常发生在文件传送的过程中。比如你在网路上下载一个可执行文件,并且偏偏在你的Linux系统中就是难以执行,那就可能是档案的属性被改变了。并且从网路上传送到你的Linux系统中,文件的属性权限确实是会被改变的
2.Linux目录树
对Linux系统和用户来说,所有可操作的计算机资源都存在于目录树这个逻辑结构中,对计算机资源的访问都可以觉得是目录树的访问。就硬碟来说,所有对硬碟的访问都弄成了对目录树中某个节点也就是文件夹的访问,访问时不须要晓得它是硬碟还是硬碟中的文件夹。
目录树的逻辑结构也十分简单linux命令详解词典,就是从根目录(/)开始,不断向上展开各级子目录。
3.硬碟分区
硬碟分区是硬碟结合到文件体系的第一步,本质是「硬盘」这个数学概念转换成「区」这个逻辑概念,为下一步低格做打算。
所以分本身并不是必须的,你完全可以把一整块硬碟作为一个区。但从数据的安全性以及系统性能角度来看,分区还是有好多好处的,所以通常还会对硬碟进行分区。
讲分区就不得不先提每块硬碟上最重要的第一磁道,这个磁道中有硬碟主引导记录(Masterbootrecord,MBR)及分区表(partitiontable),其中MBR占有446bytes,而分区表占有64bytes。硬碟主引导记录放有最基本的引导加载程序,是系统开机启动的关键环节,在附表中有更详尽的说明。而分区表则跟分区有关,它记录了硬碟分区的相关信息,但因分区表仅有64bytes,所以最多只能记彔四块分区(分区本身似乎就是对分区表进行设置)。
只能分四个区实在太少了,于是就有了扩充分区的概念,既然第一个磁道所在的分区表只能记录四条数据,那我能否借助额外的磁道来记录更多的分区信息。
把普通可以访问的分区称为主分区,扩充分区不同于主分区,它本身并没有内容,它是为进一步逻辑分区提供空间的。在某块分区指定为扩充分区后,就可以对这块扩充分区进一步分成多个逻辑分区。操作系统规定:
四块分区每块都可以是主分区或扩充分区扩充分区最多只能有一个(也没必要有多个)扩充分区可以进一步分割为多个逻辑分区扩充分区只是逻辑概念,本身不能被访问,也就是不能被低格后作为数据访问的分区,还能作为数据访问的分区只有主分区和逻辑分区逻辑分区的数目依操作系统而不同,在Linux系统中,IDE硬碟最多有59个逻辑分区(5号到63号),SATA硬碟则有11个逻辑分区(5号到15号)
通常给硬碟进行分区时,一个主分区一个扩充分区,之后把扩充分区界定为N个逻辑分区是最好的
是否可以不要主分区呢?不晓得,但似乎不用管,你创建分区的时侯会手动给你配置类型
特殊的,你最好单独分一个swap区(显存置换空间),它独为一类,功能是:当有数据被储存在数学显存上面,而且这种数据又不是常被CPU所取用时,这么那些不常被使用的程序将会被丢到硬碟的swap置换空间当中,而将速率较快的数学显存空间释放下来给真正须要的程序使用
4.低格
我们晓得Linux操作系统支持好多不同的文件系统,例如ext2、ext3、XFS、FAT等等,而Linux把对不同文件系统的访问交给了VFS(虚拟文件系统),VFS能访问和管理各类不同的文件系统。所以有了区以后就须要把它格式化成具体的文件系统便于VFS访问。
标准的Linux文件系统Ext2是使用「基于inode的文件系统」
我们晓得通常操作系统的文件数据不仅文件实际内容外,还带有好多属性,比如Linux操作系统的文件权限(rwx)与文件属性(拥有者、群组、时间参数等),文件系统一般会将属性和实际内容这两部份数据分别储存在不同的区块
在基于inode的文件系统中,权限与属性放置到inode中,实际数据放在datablock区块中,但是inode和datablock都有编号
Ext2文件系统在此基础上
文件系统最上面有一个启动磁道(bootsector)
这个启动磁道可以安装开机管理程序,这个设计让我们能将不同的引导装载程序安装到某些的文件系统后端,而不用覆盖整个硬碟惟一的MBR,也就是这样就能实现多重引导的功能
把每位区进一步分为多个块组(blockgroup),每位块组有独立的inode/block体系
假如文件系统高达数百GB时,把所有的inode和block通通置于一起会由于inode和block的数目太庞大,不容易管理
这似乎挺好理解,由于分区是用户的分区,实际计算机管理时还有个最适宜的大小,于是计算机会进一步的在分区短发块
(但这样岂不是可能出现大文件放不了的问题?有哪些机制善后吗?)
每位块组实际都会分为分为6个部份,不仅inodetable和datablock外还有4个附属模块,起到优化和建立系统性能的作用
所以整个分区大约会这样界定:
1.inodetable
主要记录文件的属性以及该文件实际数据是放置在什么block中,它记录的信息起码有这种:
大小、真正内容的block号码(一个或多个)
访问模式(read/write/excute)
拥有者与群组(owner/group)
各类时间:构建或状态改变的时间、最近一次的读取时间、最近更改的时间
没有文件名!文件名在目录的block中!
一个文件占用一个inode,每位inode有编号
Linux系统存在inode号被用完但c盘空间还有剩余的情况
注意,这儿的文件不单单是普通文件,目录文件也就是文件夹虽然也是一个文件,还有其他的也是
inode的数目与大小在低格时就早已固定了,每位inode大小均固定为128bytes(新的ext4与xfs可设定到256bytes)
文件系统才能构建的文件数目与inode的数目有关,存在空间还够但inode不够的情况
系统读取文件时须要先找到inode,并剖析inode所记录的权限与使用者是否符合,若符合才才能开始实际读取block的内容
inode要记录的资料十分多,但偏偏又只有128bytes,而inode记录一个block号码要花掉4byte,假定我一个文件有400MB且每位block为4K时,这么起码也要十万条block号码的记录!inode哪有那么多空间来储存?因此我们的系统很聪明的将inode记录block号码的区域定义为12个直接,一个间接,一个双间接与一个三间接记录区(详尽见附表)
2.datablock
放置文件内容数据的地方
在低格时block的大小就固定了,且每位block都有编号,以便捷inode的记录
原则上,block的大小与数目在低格完就不能否再改变了(除非重新低格)
在Ext2文件系统中所支持的block大小有1K,2K及4K三种,因为block大小的区别,会造成该文件系统才能支持的最大c盘容量与最大单一文件容量各不相同:
Block大小1KB2KB4KB
最大单一档案限制16GB256GB2TB
最大档案系统总容量2TB8TB16TB
每位block内最多只才能放置一个文件的资料,但一个文件可以置于多个block中(大的话)
若文件大于block,则该block的剩余容量就不能否再被使用了(c盘空间会浪费)
所以假如你的档案都十分小,而且你的block在低格时却选用最大的4K时,可能会形成容量的浪费
既然大的block可能会形成较严重的硬碟容量浪费,这么我们是否就将block大小定为1K?这也不妥,由于假如block较小的话,这么小型档案将会占用数目更多的block,而inode也要记录更多的block号码,此时将可能造成档案系统不良的读写效能
事实上现今的c盘容量都太大了,所以通常还会选择4K的block大小
3.superblock
记录整个文件系统相关信息的地方,通常大小为1024bytes,记录的信息主要有:
block与inode的总数
未使用与已使用的inode/block数目
一个validbit数值,若此文件系统已被挂载,则validbit为0,若未被挂载,则validbit为1
block与inode的大小(block为1,2,4K,inode为128bytes或256bytes);
其他各类文件系统相关信息:filesystem的挂载时间、最近一次写入资料的时间、最近一次检验硬碟(fsck)的时间
Superblock是十分重要的,没有Superblock,就没有这个文件系统了,因而假如superblock挂掉了,你的文件系统可能就须要耗费好多时间去拯救
每位块都可能富含superblock,并且我们也说一个文件系统应当仅有一个superblock而已,那是怎样回事?事实上不仅第一个块内会富含superblock之外,后续的块不一定富含superblock,而若富含superblock则该superblock主要是做为第一个块内superblock的备份,这样可以进行superblock的搜救
4.FilesystemDescription
文件系统描述
这个区段可以描述每位blockgroup的开始与结束的block号码,以及说明每位区段(superblock,bitmap,inodemap,datablock)分别介于哪一个block号码之间
5.blockbitmap
块对照表
假如你想要新增文件时要使用那个block来记录呢?其实是选择「空的block」来记录。那你如何晓得那个block是空的?这就得要通过blockbitmap了,它会记录什么block是空的,因而我们的系统就能否很快速的找到可使用的空间来记录
同样在你删掉个别文件时,这些文件本来占用的block号码就得要释放下来,此时在blockbitmap中对应当block号码的标志位就得要更改成为「未使用中」
6.inodebitmap
与blockbitmap是类似的功能,只是blockbitmap记录的是使用与未使用的block号码,至于inodebitmap则是记录使用与未使用的inode号码
5.挂载
在一个区被低格为一个文件系统以后,它就可以被Linux操作系统使用了,只是这个时侯Linux操作系统还找不到它,所以我们还须要把这个文件系统「注册」进Linux操作系统的文件体系里,这个操作就叫「挂载」(mount)。
挂载是借助一个目录当作步入点(类似选一个现成的目录作为代理),将文件系统放置在该目录下,也就是说,步入该目录就可以读取该文件系统的内容,类似整个文件系统只是目录树的一个文件夹(目录)。
这个步入点的目录我们称为「挂载点」。
因为整个Linux系统最重要的是根目录,因而根目录一定须要挂载到某个分区。而其他的目录则可依用户自己的需求来给与挂载到不同的分去。
到这儿Linux的文件体系的建立过程虽然早已大体讲完了,总结一下就是:硬碟经过分区和低格,每位区都成为了一个文件系统,挂载这个文件系统后就可以让Linux操作系统通过VFS访问硬碟时跟访问一个普通文件夹一样。这儿通过一个在目录树中读取文件的实际反例来细讲一下目录文件和普通文件。
6.目录树的读取过程
首先我们要晓得
每位文件(不管是通常文件还是目录文件)就会占用一个inode根据文件内容的大小来分配一个或多个block给该文件使用创建一个文件后,文件完整信息分布在3处地方,生成2个新文件:
3.1文件名记录在该文件所在目录的目录文件的block中,没有新文件生成
3.2文件属性、权限信息、记录具体内容的block编号记录在inode中,inode是新生成文件
3.3文件具体显存记录在block中,block是新生成文件由于文件名的记录是在目录的block当中,「新增/删掉/改名文件名」与目录的w权限有关
所以在Linux/Unix中,文件名称只是文件的一个属性,叫别称也好,叫外号也罢,仅为了便捷用户记忆和使用,但系统内部并不须要用文件名来定为文件位置,这样处理最直观的益处就是,你可以对正在使用的文件更名,换目录,甚至放在废茅房,都不会影响当前文件的使用,这在Windows里是难以想像的。例如你打开个Word文件,之后对其进行重命名操作,Windows会告诉你门儿都没有,关掉文件先!但在Mac里就毫无压力,由于Mac的操作系统同样采用了inode的设计。
创建文件过程
当在ext2下构建一个通常文件时,ext2会分配一个inode与相对于该文件大小的block数目给该文件
比如:假定我的一个block为4Kbytes,而我要构建一个100KBytes的文件,这么linux将分配一个inode与25个block来存储该文件但同时请注意,因为inode仅有12个直接指向,因而还要多一个block来作为区块号码的记录
创建目录过程
当在ext2文件系统构建一个目录时(就是新建了一个目录文件),文件系统会分配一个inode与起码一块block给该目录
inode记录该目录的相关权限与属性,并记录分配到的那块block号码而block则是记录在这个目录下的文件名与该文件对应的inode号block中都会手动生成两条记录,一条是.文件夹记录,inode指向自身,另一条是..文件夹记录,inode指向父文件夹
从目录树中读取某个文件过程
由于文件名是记录在目录的block当中,因而当我们要读取某个文件时,就一定会经过目录的inode与block,之后才才能找到那种待读取文件的inode号码,最终就会读到正确的文件的block内的资料。因为目录树是由根目录开始,因而操作系统先通过挂载信息找到挂载点的inode号,由此得到根目录的inode内容,并根据该inode读取根目录的block信息,再一层一层的往下读到正确的文件。
举例来说,假如我想要读取/etc/passwd这个文件时,系统是怎样读取的呢?
先看一下这个文件以及有关路径文件夹的信息:
1$ ll -di / /etc /etc/passwd
2 128 dr-xr-x r-x . 17 root root 4096 May 4 17:56 /
333595521 drwxr-x r-x . 131 root root 8192 Jun 17 00:20 /etc
436628004 -rw-r-- r-- . 1 root root 2092 Jun 17 00:20 /etc/passwd
复制代码
于是该文件的读取流程为:
/的inode:
通过挂载点的信息找到inode号码为128的根目录inode,且inode规定的权限让我们可以读取该block的内容(有r与x)/的block:
经过上个步骤取得block的号码,并找到该内容有etc/目录的inode号码(33595521)etc/的inode:
读取33595521号inode得悉具有r与x的权限,因而可以读取etc/的block内容etc/的block:
经过上个步骤取得block号码,并找到该内容有passwd文件的inode号码(36628004)passwd的inode:
读取36628004号inode得悉具有r的权限,因而可以读取passwd的block内容passwd的block:
最后将该block内容的资料读下来