文件管理
长期存储信息的三个基本要求
- 能够存储大量信息
- 使用信息的进程终止时,信息仍旧存在
- 信息能够并发访问
磁盘
磁盘接口
- IDE
(ATA)全称 Advanced Technology Attachment,接口速度最大为 133MB/s,因为并口线的抗干扰性太差,且排线占用空间较大,不利电脑内部散热,已逐渐被 SATA 所取代
- SATA
全称 Serial ATA,也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多,支持热插拔等功能。SATA-II 的接口速度为 300MiB/s,而 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便
- SCSI
全称是 Small Computer System Interface(小型机系统接口),SCSI 硬盘广为工作站以及个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵
- SAS
Serial Attached SCSI是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也通过缩小连接线改善系统内部空间等
文件
文件命名
一些常见的文件系统:
- FAT-16
- FAT-32
- exFAT
- NTFS
- ReFS
操作系统对文件的命名规则大多允许1-8个字母组成,并且根据约定,有的使用点号分割文件名与扩展名
在部分操作系统中,扩展名不是必须的
文件结构
- 字节序列
- 记录序列:以特定的长度管理字符,称之为一个记录,很像数据库的表结构
- 树
文件类型
- 普通文件
- 目录
文件访问
- 顺序访问 read
- 随机访问 lseek
文件属性
- 文件的元数据
文件属性 | 意义 |
---|---|
保护 | 谁能访问该文件,以何种方式访问 |
密码 | 访问该文件需要的密码 |
创立者 | 创立该文件的用户的ID |
拥有者 | 文件当前的拥有者 |
只读标志 | 0读写访问;1只读. |
隐藏标志 | 0正常文件; 1隐藏文件 |
系统标志 | 0正常文件; 1系统文件 |
归档标志 | 0已经备份; 1需要备份 |
ASCIIV二进制标志 | 0文本文件; 1二进制文件 |
随机访问标志 | 0顺序访问; 1随机访问 |
临时文件标志 | 0正常文件; 1临时文件 |
锁标志 | 0释放状态;非零锁住状态 |
记录长度 | 一个记录包含的字节数 |
关键字位置 | 记录里关键字所处的位移量 |
关键字长度 | 关键字所占字节数 |
文件创立时间 | 文件创立的日期和时间 |
最后访向时间 | 文件最后被访问的日期和时间 |
最后修改时间 | 文件最后修改的日期和时间 |
当前文件大小 | 文件所占的字节数 |
文件最大尺寸 | 文件可达到的最大字节数 |
文件操作
- create
- delete
- open
- close
- read
- write
- append
- seek
- get attrs
- set attrs
- rename
使用文件系统调用
一个简单的C语言程序:
int main(){
FILE *fp;
char c = -1;
fp = fopen("./file.c","r");
while ((c = fgetc(fp)) != -1){
putchar(c);
}
fclose(fp);
return 0;
}
目录
一级目录系统
实现简单,用在嵌入式系统上
层次目录系统
路径名
- 绝对路径
- 相对路径
- 工作目录:对当前程序来说 使用一个状态变量记录的一个目录 这样就可以方便地使用相对路径
目录操作
- create
- delete
- opendir
- closedir
- readdir
- rename
- link
- unlink
文件系统的实现
一个分区通常只能格式化成一个文件系统,但使用磁盘阵列技术可以将一个分区格式化为多个文件系统
文件系统布局
除了MBR 不同的文件系统分区的布局也不同
- inode:一个文件占用一个inode,记录文件的属性和此文件占用的block编号
- 具体包含:权限、拥有者、容量、时间、文件特性等信息
- 每个 inode 大小均固定为 128 bytes (新的 ext4 与 xfs 可设定到 256 bytes)
- block:用来存放文件内容,一个文件可以占用多个block
- 不同block大小会限制单个文件和文件系统的最大大小
- superblock:记录文件系统的整体信息,如容量、格式
- block bitmap:一个记录block占用情况的图
MBR
- 主引导记录(MBR):在磁盘的0号扇区,用来引导计算机
MBR 中,第一个扇区最重要,里面有主要开机记录(Master boot record, MBR)及分区表(partition table),其中主要开机记录占 446 bytes,分区表占 64 bytes
分区表只有 64 bytes,最多只能存储 4 个分区,这 4 个分区为主分区(Primary)和扩展分区(Extended)。其中扩展分区只有一个,它使用其它扇区来记录额外的分区表,因此通过扩展分区可以分出更多分区,这些分区称为逻辑分区
Linux把分区当成文件,分区文件的命名方式为:磁盘文件名 + 编号,例如 /dev/sda1。注意,逻辑分区的编号从 5 开始
GPT
- 全局唯一标识分区表(GUID Partition Table,缩写:GPT)是一个实体硬盘的分区表的结构布局的标准
扇区是磁盘的最小存储单位,旧磁盘的扇区大小通常为 512 bytes,而最新的磁盘支持 4 k。GPT 为了兼容所有磁盘,在定义扇区上使用逻辑区块地址(Logical Block Address, LBA),LBA 默认大小为 512 bytes
开机检测程序
BIOS是开机的时候计算机执行的第一个程序,这个程序知道开机的磁盘,读取磁盘的第一个扇区的开机记录(MBR),通过MBR执行开机管理程序,开机管理程序加载操作系统的核心文件
MBR提供以下功能:选单、载入核心文件以及转交其它开机管理程序。转交这个功能可以用来实现多重引导,只需要将另一个操作系统的开机管理程序安装在其它分区的启动扇区上,在启动开机管理程序时,就可以通过选单选择启动当前的操作系统或者转交给其它开机管理程序从而启动另一个操作系统
FSCK
由于文件写入操作是由一系列的非原子操作组成,断电很容易出现数据的不一致问题
FSCK 通过扫描磁盘的元数据,进行比对是否一致,如果出现不一致,就按照某些策略对元数据进行修正,这个时间一般会很长
文件的实现
连续分配
这种方式只需要2个数字能记录一个文件,并且也容易进行读操作,读操作的性能较好
连续分配一般被用在CD DVD等事前就知道文件大小并且文件大小不会改变的场景中
链表分配
使用内存中的表进行链表分配
- 文件分配表(FAT)
在内存中维护一张表,存储每个文件的指针
这种方式只适合小磁盘,大磁盘需要很大的内存维护这张表
i节点
每个文件使用固定的指针指向磁盘块,如果文件大小超过8个固定磁盘块,则在最后使用一个指针指向一个磁盘块链表
目录的实现
第一种方式的问题在于如果某一个文件移除后,就会形成一个大小不可知的磁盘空隙,久了会形成磁盘碎片
第二种方式是建立在每个文件项的大小都是一样的基础上,但是还是需要处理堆中文件名的空隙
如果想要根据文件名查找文件,则需要对整个文件名进行扫描,当文件数量较多是,为加快速度,可使用散列表或者缓存加速查找
共享文件
在目录树节点中,两个节点指向的是同一份文件
链接
目录不直接指向磁盘块,而是指向一块描述文件的数据结构
符号链接
- 一种特殊化的文件类型 存的是文件的实际路径,当读取符号链接时,做一个转发
日志结构文件系统(LFS)
所有的写操作先被缓存在内存中,等待一段时间批量写入
使用日志的结构管理文件,使用一个清理线程周期性进行磁盘压缩
日志文件系统
- 具备幂等与原子性
这点是跟数据库的事务恢复借鉴的
使用一块日志区用来把要做的操作先记录下来,然后再执行真正的操作,这也就是先写日志
通过某种记录日志的方式,让这些操作一旦决定被提交,即使后续对磁盘上元数据和数据块上数据结构的改动进行到一半,系统断电了,仍然可以根据这个日志恢复,核心还是redo log
虚拟文件系统
- 使用统一的接口包装不同的文件系统,对用户和进程透明
是适配器设计模式和面向接口编程的一个实例
实现:
每个文件系统在装载时,都会向VFS注册一系列的函数地址,这样VFS在需要时,就可直接调用相对应的函数实现相应的功能
文件系统管理和优化
磁盘空间管理
选择块大小 速度与空间不可兼得 越小的块空间利用率越高 但读取效率越低
记录空闲块
- 磁盘配额
对于每个用户打开的文件,都会有一个指向配额表的指针,在读取或者写入或者登录的时候,会检查当前用户是否超过了限制
文件系统备份
- 物理转储:直接复制物理磁盘块
- 逻辑转储:从特定的几个目录开始,标记修改过的i节点进行复制
文件系统的一致性
UNIX下的fsck Windows下的scandisk
- 块的一致性检查:检查磁盘使用的块与空闲块是否一致
- 文件的一致性检查
- 链接文件的计数器是否跟实际的链接数一致
- 一些奇怪的文件状态 如文件所有者没有权限读写 其他用户却有
文件系统性能
- 高速缓存
其使用了一块内存来加速磁盘与CPU之间的读写速度,但这块内存再逻辑上是属于磁盘的,需要注意的一些问题就是缓存的淘汰,还有就是写在缓存上的数据什么时候要写到磁盘,像UNIX 有个sync系统调用强制写入缓存,而在Windows 只要一写入缓存,就会把至上次写入有变动的块全部刷到磁盘
- 块提前读
根据空间局部性,读取当前块时,读取下一块数据的可能性很高,操作系统提前读入下一块放入缓存可以有效提高性能。不过这点跟文件是顺序读写还是随机读写有很大的关系
- 减少磁盘臂运动
磁盘碎片整理
- 同内存紧缩对已使用进行磁盘块进行移动 腾出较大的连续空间