一种磁盘文件系统的设计
近日和朋友聊到存储系统设计的相关技术,结合以前我在互联网公司做分布式系统的一些经验,本篇就粗略地讲一讲如何设计一个简单的磁盘文件系统。
传统的磁盘结构是像下面这个样子的,它有一个或多个盘片,用于存储数据。盘片多采用铝合金材料;中间有一个主轴,所有的盘片都绕着这个主轴转动。一个组合臂上面有多个磁头臂,每个磁头臂上面都有一个磁头,负责读写数据。
磁盘一般有一个或多个盘片。每个盘片可以有两面,即第一个盘片的正面为0面,反面为 1 面;第二个盘片的正面为 2 面…依次类推。磁头的编号也和盘面的编号是一样的,因此有多少个盘面就有多少个磁头。盘面正视图如下图,磁头的传动臂只能在盘片的内外磁道之间移动。因此不管开机还是关机,磁头总是在盘片上面。关机时,磁头停在盘片上面,抖动容易划伤盘面造成数据损失,为了避免这样的情况,所以磁头都是停留在起停区的,起停区是没有数据的。
每个盘片的盘面被划分成多个狭窄的同心圆环,数据就存储在这样的同心圆环上面,我们将这样的圆环称为磁道 (Track)。每个盘面可以划分多个磁道,最外圈的磁道是0号磁道,向圆心增长依次为1磁道、2磁道…磁盘的数据存放就是从最外圈开始的。
根据硬盘的规格不同,磁道数可以从几百到成千上万不等。每个磁道可以存储数 Kb 的数据,但是计算机不必要每次都读写这么多数据。因此,再把每个磁道划分为若干个弧段,每个弧段就是一个扇区 (Sector)。扇区是硬盘上存储的物理单位,现在每个扇区可存储 512 字节数据已经成了业界的约定。也就是说,即使计算机只需要某一个字节的数据,但是也得把这个 512 个字节的数据全部读入内存,再选择所需要的那个字节。
柱面是我们抽象出来的一个逻辑概念,简单来说就是处于同一个垂直区域的磁道称为柱面 ,即各盘面上面相同位置磁道的集合。需要注意的是,磁盘读写数据是按柱面进行的,磁头读写数据时首先在同一柱面内从 0 磁头开始进行操作,依次向下在同一柱面的不同盘面(即磁头上)进行操作,只有在同一柱面所有的磁头全部读写完毕后磁头才转移到下一柱面。因为选取磁头只需通过电子切换即可,而选取柱面则必须通过机械切换。数据的读写是按柱面进行的,而不是按盘面进行,所以把数据存到同一个柱面是很有价值的。
磁盘被磁盘控制器所控制(可控制一个或多个),它是一个小处理器,可以完成一些特定的工作。比如将磁头定位到一个特定的半径位置;从磁头所在的柱面选择一个扇区;读取数据等。
现代硬盘寻道都是采用CHS(Cylinder Head Sector)的方式,硬盘读取数据时,读写磁头沿径向移动,移到要读取的扇区所在磁道的上方,这段时间称为寻道时间(seek time)。因读写磁头的起始位置与目标位置之间的距离不同,寻道时间也不同。磁头到达指定磁道后,然后通过盘片的旋转,使得要读取的扇区转到读写磁头的下方,这段时间称为旋转延迟时间(rotational latencytime)。然后再读写数据,读写数据也需要时间,这段时间称为传输时间(transfer time)。
根据上文的信息,我们可以得出磁盘容量的计算公式为:
磁盘容量 = 总盘面数 x 每盘面柱面数 x 每磁道扇区数 x 512
注:以上信息来源于网络。
磁盘在物理上是一个很复杂的混和结构,对软件开发者来说,基本上不需要直接接触它们,我们所有的访问都在磁盘控制器的接口之一,使用与内存相似的统一寻址,只不过磁盘支持持久化,且性能相对于内存有数量级差。我们可以考虑使用静态链表来设计文件系统。
静态链表是一种利用顺序存储结构来进行链式存储的特殊结构,使用它可以在一段连接的存储空间模拟离散的链式结构。它通过将整块大内存划分为小的块,块与块之间通过指针连接,这个小的块,我称为之存储单元。
在存储单元之上,一个基本的文件系统需要有逻辑的目录、文件,通常一个块不可能存储完整个目录或文件,因此它们实际上可能需要跨多个块。下面是存储单元和目录结构的定义:
存储单元结构定义:
目录结构定义:
文件结构定义:
纯文件内容
此外,还需要有空闲单元结构等信息,这里增加一个全局磁盘信息定义:
下面以一个64K的磁盘,假设起始地址从0开始,最大地址64K-1,对于如下的逻辑存储:
假设定义每单元大小为4K,在4K字节中,需要存储单元头32字节,其余4K-32可存储目录或文件内容,假设在下面的设计中,每个单元若存储文件内容最多不超过3K。且假设定义全局磁盘信息在0单元,其实际物理布局如下:
一个合格的文件系统至少应支持以下操作:
包括低级格式化和高级格式化,低级格式化由厂商提供,由控制器提供支持,主要用于消除数据,重建扇区存储结构。高级格式化由操作系统提供,主要目的是向固定扇区写入特定结构,这些结构包括磁盘或分区元信息表,管理整个磁盘或分区的全局和入口信息。
对我们的简单系统来说,需要初使化全局信息地址和根目录,以及各存储单元,初使化为:
首先需要找到父目录所在的单元位置,由于整个文件系统是一个树型结构,需要从根目录位置开始寻找。若在根目录添加,或者说找到了父目录的单元地址,操作如下:
删除目录是上面新增目录的逆操作,操作步骤:
遍历通常实现为一个递归的过程,对每个递归单元来说,逻辑如下:
首先需要提供父目录位置,即目录存储单元地址,以在根目录添加文件为例,操作如下:
需要提供文件的存储单元地址,以向上面的8K地址写入abcdefg内容为例,操作如下:
需要提供文件的存储单元地址,以向上面的8K地址读取为例,操作如下:
是新增文件的反操作,操作如下:
可以用GFS在“不可靠”的硬件上设计文件系统。
GFS是一个可扩展的分布式文件系统,用于大型的、分布式的、对大量数据进行访问的应用。它运行于廉价的普通硬件上,并提供容错功能。它可以给大量的用户提供总体性能较高的服务。GFS 也就是 google File System,Google公司为了存储海量搜索数据而设计的专用文件系统。
设计特点、分布式能力、性能、容灾、维护和扩展、成本
分布式文件系统主要关键技术:
全局名字空间、缓存一致性、安全性、可用性、可扩展性
即在存储设备上组织文件的方法。
操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。
文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性。
从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。
3.1Linux 文件系统类型
不同的操作系统使用不同类型的文件系统,为了与其他的操作系统兼容,以相互交换数据,
通常,每种操作系统都支持多种类型的文件系统。
Linux 中保存数据的磁盘分区通常采用EXT2/EXT3 文件系统,而实现虚拟存储的swap 分区
采用swap 文件系统,同时Linux 内核支持十多种不同的文件系统。
1. EXT2 和EXT3 文件系统
EXT(Extended File System,扩展文件系统)是专为Linux 设计的文件系统。在Linux 发展
早起,起到重要中用,但在稳定性、速度和兼容性方面存在缺陷。
EXT2 是为解决EXT 系统存在的缺陷而设计的可扩展、高性能的文件系统。
EXT3 是EXT2 的增强版本,在EXT2 的基础上,增加了文件系统的日志管理功能。
EXT3 文件系统具有的特点:
(1) 高效性:当系统因为异常断电或系统崩溃,重新启动时不需要检查文件系统的一致
性,只需要根据文件系统的日志,快速检测并恢复文件系统到正常状态。
(2) 数据的完整性:可以保持数据域文件系统状态的高度一致性,避免意外关机对文件
系统造成的破坏。
(3) 数据的存取速度更快:EXT3 文件系统的日志功能对磁盘驱动器的读/写进行优化,
使读/写系统的速度更快。
(4) 数据易于转换
2. swap 文件系统
用于Linux 的交换分区。在Linux 中,使用整个交换分区来提供虚拟内存。
3. VFAT 文件系统
VFAT 是Linux 对DOS、Windows 系统下的FAT 文件系统的统称。
4. NFS 文件系统
NFS 即网络文件系统,用在UNIX 或Linux 系统间通过网络进行文件共享。
5. SMB 文件系统
SMB 是Samba 的缩写,是另一种网络文件系统,用于在Windows 和Linux 系统之间共享文
件和打印机。
6. ISO9660 文件系统
CD-ROM使用的标准文件系统。
此外,Linux 支持的文件系统还有minix、msdos、ncpfs、hpfs、umsdos 等。
3.2 Linux 的目录和文件
1.Linux 系统的目录结构
Linux 文件系统由文件和目录组成,文件是专门用来存储数据的对象,目录是一种用来组织
文件和其他目录的容器。Linux 和DOS、Windows 系统一样,使用树形目录结构来组织和管
理文件。
1. / 文件系统的入口,最高一级目录;
2. /bin 基础系统所需要的命令位于此目录,是最小系统所需要的命令,如:ls, cp, mkdir等。
这个目录中的文件都是可执行的,一般的用户都可以使用。
3. /boot 包含Linux内核及系统引导程序所需要的文件,比如vmlinuz initrd.img文件都位于这个目录中。在一般情况下,GRUB或LILO系统引导管理器也位于这个目录;
4. /dev 设备驱动程序文件存储目录,比如声卡、磁盘等,是Linux文件系统的一个闪亮的特性-所有对象都是文件或目录。仔细观察这个目录你会发现hda1, hda2等,它们代表系统主硬盘的不同分区。
5. /etc 存放系统程序或者一般工具的配置文件。
如安装了apache2之后,配置文件在/etc/apache2/目录下。
/etc/init.d这个目录是用来存放系统或服务器以System V模式启动的脚本,这在以System V模式启动或初始化的系统中常见。
6. /home 普通用户默认存放目录Linux是多用户环境,所以每一个用户都有一个只有自己可以访问的目录(当然管理员也可以访问)。它们以/home/username的方式存在。这个目录也保存一些应用对于这个用户的配置,比如IRC, X等。
7. /lib 库文件存放目录这里包含了系统程序所需要的所有共享库文件,类似于Windows的共享库DLL文件。
8. /var 这个目录的内容是经常变动,因为存储的文件,如数据库,数据文件大小是在不断的增大。
/var/log这是用来存放系统日志的目录。
/var/www目录是定义Apache服务器站点存放目录;/var/lib用来存放一些库文件,比如MySQL的,以及MySQL数据库的的存放地;
/var/log系统日志存放,分析日志要看这个目录的东西;
/var/spool打印机、邮件、代理服务器等假脱机目录;
9. /lost+found 在ext2或ext3文件系统中,当系统意外崩溃或机器意外关机,而产生一些文件碎片放在这里。当系统启动的过程中fsck工具会检查这里,并修复已经损坏的文件系统。 有时系统发生问题,有很多的文件被移到这个目录中,可能会用手工的方式来修复,或移到文件到原来的位置上。
Linux应该正确的关机。但有时你的系统也可能崩溃掉或突然断电使系统意外关机。那么启动的时候fsck将会进行长时间的文件系统检查。Fsck会检测并试图恢复所发现的'不正确的文件。被恢复的文件会放置在这个目录中。所恢复的文件也许并不完整或并不合理,但毕竟提供了一些恢复数据的机会。
10. /media 即插即用型存储设备的挂载点自动在这个目录下创建,比如USB盘系统自动挂载后,会在这个目录下产生一个目录 ;CDROM/DVD自动挂载后,也会在这个目录中创建一个目录,类似cdrom的目录。这个只有在最新的发行套件上才有. 10. /mnt /mnt这个目录一般是用于存放挂载储存设备的挂载目录的,比如有cdrom等目录。有时我们可以把让系统开机自动挂载文件系统,把挂载点放在这里也是可以的。比如光驱可以挂载到/mnt/cdrom。
11. /opt 表示的是可选择的意思,有些软件包也会被安装在这里,也就是自定义软件包,比如在Fedora Core 5.0中,OpenOffice就是安装在这里。有些我们自己编译的软件包,就可以安装在这个目录中;通过源码包安装的软件,可以通过./configure --prefix=/opt/,将软件安装到opt目录。
这个目录包含所有默认系统安装之外的软件和添加的包。
12. /proc 操作系统运行时,进程(正在运行中的程序)信息及内核信息(比如cpu、硬盘分区、内存信息等)存放在这里。/proc目录是伪装的文件系统proc的挂载目录,proc并不是真正的文件系统。
这是系统中极为特殊的一个目录,实际上任何分区上都不存在这个目录。它实际是个实时的、驻留在内存中的文件系统。
13. /root Linux超级权限用户root的家目录;
14. /sbin 大多是涉及系统管理的命令的存放,是超级权限用户root的可执行命令存放地,普通用户无权限执行这个目录下的命令;
这个目录和
/usr/sbin/usr/X11R6/sbin或/usr/local/sbin目录是相似的; 我们记住就行了,凡是目录sbin中包含的都是root权限才能执行的。
15. /tmp 临时文件目录,有时用户运行程序的时候,会产生临时文件。/tmp就用来存放临时文件的。/var/tmp目录和这个目录相似。
许多程序在这里建立lock文件和存储临时数据。有些系统会在启动或关机时清空此目录。
16. /usr 这个是系统存放程序的目录,比如命令、帮助文件等。
这个目录下有很多的文件和目录。
当我们安装一个Linux发行版官方提供的软件包时,大多安装在这里。
如果有涉及服务器配置文件的,会把配置文件安装在/etc目录中。
#include<string.h>
#include<stdlib.h>
#define MEM_D_SIZE 1024*1024//总磁盘空间为1M
#define DISKSIZE 1024 //磁盘块的大小1K
#define DISK_NUM 1024 //磁盘块数目1K
#define FATSIZE DISK_NUM*sizeof(struct fatitem) //FAT表大小
#define ROOT_DISK_NO FATSIZE/DISKSIZE+1 //根目录起始盘块号
#define ROOT_DISK_SIZE sizeof(struct direct) //根目录大小
#define DIR_MAXSIZE 1024 //路径最大长度为1KB
#define MSD 5 //最大子目录数5
#define MOFN 5 //最大文件深度为5
#define MAX_WRITE 1024*128 //最大写入文字长度128KB
struct fatitem
{
int item
char em_disk
}
struct direct
{
struct FCB
{
char name[9]
char property
int size
int firstdisk
int next
int sign
}directitem[MSD+2]
}
struct opentable
{
struct openttableitem
{
char name[9]
int firstdisk
int size
}openitem[MOFN]
int cur_size
}
struct fatitem *fat
struct direct *root
struct direct *cur_dir
struct opentable u_opentable
int fd=-1
char *bufferdir
char *fdisk
void initfile()
void format()
void enter()
void halt()
int create(char *name)
int open(char *name)
int close(char *name)
int write(int fd,char *buf,int len)
int read(int fd,char *buf)
int del(char *name)
int mkdir(char *name)
int rmdir(char *name)
void dir()
int cd(char *name)
void print()
void show()
void initfile()
{
fdisk = (char *)malloc(MEM_D_SIZE*sizeof(char))
format()
}
void format()
{
int i
FILE *fp
fat = (struct fatitem *)(fdisk+DISKSIZE)
fat[0].item=-1
fat[0].em_disk='1'
for(i=1i<ROOT_DISK_NO-1i++)
{
fat[i].item=i+1
fat[i].em_disk='1'
}
fat[ROOT_DISK_NO].item=-1
fat[ROOT_DISK_NO].em_disk='1'
for(i=ROOT_DISK_NO+1i<DISK_NUMi++)
{
fat[i].item = -1
fat[i].em_disk = '0'
}
root = (struct direct *)(fdisk+DISKSIZE+FATSIZE)
root->directitem[0].sign = 1
root->directitem[0].firstdisk = ROOT_DISK_NO
strcpy(root->directitem[0].name,".")
root->directitem[0].next = root->directitem[0].firstdisk
root->directitem[0].property = '1'
root->directitem[0].size = ROOT_DISK_SIZE
root->directitem[1].sign = 1
root->directitem[1].firstdisk = ROOT_DISK_NO
strcpy(root->directitem[1].name,"..")
root->directitem[1].next = root->directitem[0].firstdisk
root->directitem[1].property = '1'
root->directitem[1].size = ROOT_DISK_SIZE
if((fp = fopen("disk.dat","wb"))==NULL)
{
printf("Error:\n Cannot open file \n")
return
}
for(i=2i<MSD+2i++)
{
root->directitem[i].sign = 0
root->directitem[i].firstdisk = -1
strcpy(root->directitem[i].name,"")
root->directitem[i].next = -1
root->directitem[i].property = '0'
root->directitem[i].size = 0
}
if((fp = fopen("disk.dat","wb"))==NULL)
{
printf("Error:\n Cannot open file \n")
return
}
if(fwrite(fdisk,MEM_D_SIZE,1,fp)!=1)
{
printf("Error:\n File write error! \n")
}
fclose(fp)
}
void enter()
{
FILE *fp
int i
fdisk = (char *)malloc(MEM_D_SIZE*sizeof(char))
if((fp=fopen("disk.dat","rb"))==NULL)
{
printf("Error:\nCannot open file\n")
return
}
if(!fread(fdisk,MEM_D_SIZE,1,fp))
{
printf("Error:\nCannot read file\n")
exit(0)
}
fat = (struct fatitem *)(fdisk+DISKSIZE)
root = (struct direct *)(fdisk+DISKSIZE+FATSIZE)
fclose(fp)
for(i=0i<MOFNi++)
{
strcpy(u_opentable.openitem[i].name,"")
u_opentable.openitem[i].firstdisk = -1
u_opentable.openitem[i].size = 0
}
u_opentable.cur_size = 0
cur_dir = root
bufferdir = (char *)malloc(DIR_MAXSIZE*sizeof(char))
strcpy(bufferdir,"Root:")
}
void halt()
{
FILE *fp
int i
if((fp=fopen("disk.dat","wb"))==NULL)
{
printf("Error:\nCannot open file\n")
return
}
if(!fwrite(fdisk,MEM_D_SIZE,1,fp))
{
printf("Error:\nFile write error!\n")
}
fclose(fp)
free(fdisk)
free(bufferdir)
return
}
int create(char *name)
{
int i,j
if(strlen(name)>8)
return(-1)
for(j=2j<MSD+2j++)
{
if(!strcmp(cur_dir->directitem[j].name,name))
break
}
if(j<MSD+2)
return(-4)
for(i=2i<MSD+2i++)
{
if(cur_dir->directitem[i].firstdisk==-1)
break
}
if(i>=MSD+2)
return(-2)
if(u_opentable.cur_size>=MOFN)
return(-3)
for(j=ROOT_DISK_NO+1j<DISK_NUMj++)
{
if(fat[j].em_disk=='0')
break
}
if(j>=DISK_NUM)
return(-5)
fat[j].em_disk = '1'
strcpy(cur_dir->directitem[i].name,name)
cur_dir->directitem[i].firstdisk = j
cur_dir->directitem[i].size = 0
cur_dir->directitem[i].next = j
cur_dir->directitem[i].property = '0'
fd = open(name)
return 0
}
int open(char *name)
{
int i, j
for(i=2i<MSD+2i++)
{
if(!strcmp(cur_dir->directitem[i].name,name))
break
}
if(i>=MSD+2)
return(-1)
if(cur_dir->directitem[i].property=='1')
return(-4)
for(j=0j<MOFNj++)
{
if(!strcmp(u_opentable.openitem[j].name,name))
break
}
if(j<MOFN)
return(-2)
if(u_opentable.cur_size>=MOFN)
return(-3)
for(j=0j<MOFNj++)
{
if(u_opentable.openitem[j].firstdisk==-1)
break
}
u_opentable.openitem[j].firstdisk = cur_dir->directitem[i].firstdisk
strcpy(u_opentable.openitem[j].name,name)
u_opentable.openitem[j].size = cur_dir->directitem[i].size
u_opentable.cur_size++
return(j)
}
int close(char *name)
{
int i
for(i=0i<MOFNi++)
{
if(!strcmp(u_opentable.openitem[i].name,name))
break
}
if(i>=MOFN)
return(-1)
strcpy(u_opentable.openitem[i].name,"")
u_opentable.openitem[i].firstdisk = -1
u_opentable.openitem[i].size = 0
u_opentable.cur_size--
return 0
}
int write(int fd, char *buf, int len)
{
char *first
int item, i, j, k
int ilen1, ilen2, modlen, temp
char Space = 32
char Endter= '\n'
for(i=0i<leni++)
{
if(buf[i] == '$')
buf[i] = Space
else if(buf[i] == '#')
buf[i] = Endter
}
item = u_opentable.openitem[fd].firstdisk
for(i=2i<MSD+2i++)
{
if(cur_dir->directitem[i].firstdisk==item)
break
}
temp = i
while(fat[item].item!=-1)
{
item =fat[item].item
}
first = fdisk+item*DISKSIZE+u_opentable.openitem[fd].size%DISKSIZE
if(DISKSIZE-u_opentable.openitem[fd].size%DISKSIZE>len)
{
strcpy(first,buf)
u_opentable.openitem[fd].size = u_opentable.openitem[fd].size+len
cur_dir->directitem[temp].size = cur_dir->directitem[temp].size+len
}
else
{
for(i=0i<(DISKSIZE-u_opentable.openitem[fd].size%DISKSIZE)i++)
{
first[i] = buf [i]
}
ilen1 = len-(DISKSIZE-u_opentable.openitem[fd].size%DISKSIZE)
ilen2 = ilen1/DISKSIZE
modlen = ilen1%DISKSIZE
if(modlen>0)
ilen2 = ilen2+1
for(j=0j<ilen2j++)
{
for(i=ROOT_DISK_NO+1i<DISK_NUMi++)
{
if(fat[i].em_disk=='0')
break
}
if(i>=DISK_NUM)
return(-1)
first = fdisk+i*DISKSIZE
if(j==ilen2-1)
{
for(k=0k<len-(DISKSIZE-u_opentable.openitem[fd].size%DISKSIZE)-j*DISKSIZEk++)
first[k] = buf[k]
}
else
{
for(k=0k<DISKSIZEk++)
first[k] =buf[k]
}
fat[item].item = i
fat[i].em_disk = '1'
fat[i].item = -1
}
u_opentable.openitem[fd].size = u_opentable.openitem[fd].size+len
cur_dir->directitem[temp].size = cur_dir->directitem[temp].size+len
}
return 0
}
int read(int fd, char *buf)
{
int len = u_opentable.openitem[fd].size
char *first
int i, j, item
int ilen1, modlen
item = u_opentable.openitem[fd].firstdisk
ilen1 = len/DISKSIZE
modlen = len%DISKSIZE
if(modlen!=0)
ilen1 = ilen1+1
first = fdisk+item*DISKSIZE
for(i=0i<ilen1i++)
{
if(i==ilen1-1)
{
for(j=0j<len-i*DISKSIZEj++)
buf[i*DISKSIZE+j] = first[j]
}
else
{
for(j=0j<len-i*DISKSIZEj++)
buf[i*DISKSIZE+j] = first[j]
item = fat[item].item
first = fdisk+item*DISKSIZE
}
}
return 0
}
int del(char *name)
{
int i,cur_item,item,temp
for(i=2i<MSD+2i++)
{
if(!strcmp(cur_dir->directitem[i].name,name))
break
}
文件目录、目录文件与当前目录分别是:
1、文件目录:为实现“按名存取”,必须建立文件名与辅存空间中物理地址的对应关系,体现这种对应关系的数据结构称为文件目录。
2、目录文件:为了实现文件目录的管理,通常将文件目录以文件的形式保存在外存空间,这个文件就被称为目录文件。目录文件是长度固定的记录式文件。
3、当前目录:当一个文件系统含有许多级时,每访问一个文件,都要使用从树根开始直到树叶(数据文件)为止的、包括各中间节点(目录)名的全路径名。
同时由于一个进程运行时所访问的文件大多仅局限于某个范围,因而非常不便。基于这一点,可为每个进程设置一个“当前目录”
,又称为“工作目录”。
/iknow-pic.cdn.bcebos.com/e1fe9925bc315c606df16a0e83b1cb13485477ee"target="_blank"title="点击查看大图">/iknow-pic.cdn.bcebos.com/e1fe9925bc315c606df16a0e83b1cb13485477ee?x-bce-process=image%2Fresize%2Cm_lfit%2Cw_600%2Ch_800%2Climit_1%2Fquality%2Cq_85%2Fformat%2Cf_auto"esrc="https://iknow-pic.cdn.bcebos.com/e1fe9925bc315c606df16a0e83b1cb13485477ee"/>
扩展资料
目录结构功能介绍和种类:
目录结构的组织,关系到文件系统的存取速度,也关系到文件的共享性和安全性。因此,组织好文件的目录,是设计好文件系统的重要环节。目前常用的目录结构形式有单级目录、两级目录和多级目录。
1、单级目录结构
这是最简单的目录结构。在整个文件系统中只建立一张目录表,每个文件占一个目录项,目录项中含文件名、文件扩展名、文件长度、文件类型、文件物理地址以及其它文件属性。此外,为表明每个目录项是否空闲,又设置了一个状态位。
2、两级目录
为了克服单级目录所存在的缺点,可以为每一个用户建立一个单独的用户文件目录UFD(User
FileDirectory)。这些文件目录具有相似的结构,它由用户所有文件的文件控制块组成。
此外,在系统中再建立一个主文件目录
MFD(MasterFileDirectory);
在主文件目录中,每个用户目录文件都占有一个目录项,其目录项中包括用户名和指向该用户目录文件的指针。
3、多级目录结构
对于大型文件系统,通常采用三级或三级以上的目录结构,以提高对目录的检索速度和文件系统的性能。多级目录结构又称为树型目录结构,主目录在这里被称为根目录,把数据文件称为树叶,其它的目录均作为树的结点。
文件系统有明显的缺点:
(1).编写应用程序很不方便。
应用程序的设计者必须对所用的文件的逻辑及物理结构有清楚的了解。操作系统 只能打开、关 闭、读、写等几个低级的文件操作命令,对文件的查询修改等处理都须在应用程序内解决。应用程序还 不可避免地在功能上有所重复。在文件系统上编写应用程序的效率不高。
(2).文件的设计很难满足多种应用程序的不同要求,数据冗余经常是不可避免的。
为了兼顾各种应用程序的要求,在设计文件系统时,往往不得不增加冗余的数据。数据冗余不仅浪费空间,而且会带来数据的不一致性(inconsistency).在文件系统中没有维护数据一致性的监控机制,数据的一致性完全有用户负责维护。在简单的系统中勉强能应付,但在大型复杂的系统中几乎是不可能完成的。
(3).文件结构的修改将导致应用程序的修改,应用程序的维护量将很大。
(4).文件系统不支持对文件的并发访问(concurrent access)。
(5).数据缺少统一管理,在数据的结构、编码、表示格式、命名以及输出格式等方面不容易做到规范化、标准化;数据安全和保密方面,也难以采取有效的办法。
针对文件系统的缺点,人们发展了以统一管理和共享数据为主要特征的数据库系统。在数据库系统中,数据不再仅仅服务于某个程序或用户,而是看成一个单位的共享资源,由一个叫数据库管理系统(Data Management System,简称DBMS)的软件统一管理。由于有DBMS的统一管理,应用程序不必直接介入诸如打开、关闭、读写文件等低级的操作,而由DBMS代办。用户也不必关系数据存储和其他实现的细节,可在更高的抽象级别上观察和访问数据。文件结构的一些修改也可以由DBMS屏蔽,使用户看不到这些修改,从而减少应用程序的维护工作量,提高数据的独立性。由于数据的统一管理,人们可以从全单位着眼,合理组织数据,减少数据冗余;还可以更好地贯彻规范化和标准化,从而有利于数据的转移和更大范围的共享。由于DBMS不是为某个应用程序服务,而是为整个单位服务的,DBMS做得复杂一些也是可以接受的。许多在文件系统中难以实现的动能,在DBMS中都一一实现了。
例如:适合不同类型用户的多种用户界面,保证并发访问时的数据一致性的并发控制(concurrent control),增进数据安全性(security)的访问控制(access control),在故障的情况下保证数据一致性的恢复(recovery)功能,保证数据在语义上的一致性的完整性约束(integrity constraints)检查功能等。随着计算机应用的发展,DBMS的功能愈来愈强,规模愈来愈大,复杂性和开销也随之增加。目前,在一些功能非常明确且无数据共享的简单应用系统中,为减少开销,提高性能,有时仍采用文件系统;不过在数据密集型应用系统中,基本上都使用数据库系统。
现代的数据库管理系统应该具备的7个功能:
1、提供高级的用户接口
2、查询处理和优化
这里的查询(query)泛指用户对数据库所提的访问要求,不但包含数据检索,也包括修改\定义新数据等
3、数据目录管理
4、并发控制
5、恢复功能
6、完整性约束检查
7、访问控制
数据管理和数据处理一样,都是计算机系统的最基本的支撑技术。尽管计算机科学技术经历了飞速的发展,但数据管理的这一地位没有变化。数据管理将作为计算机科学技术的一个重要分支一直发展下去,社会信息化,对数据管理的要求也愈高。