文件系统
注1:操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:与文件管理有关的软件、被管理的文件以及实施文件管理所需的数据结构。从系统角度来看,文件系统是对文件存储器空间进行组织和分配,负责文件的存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。
文件系统是操作系统用于明确磁盘或分区上的文件的方法和数据结构;即在磁盘上组织文件的方法。也指用于存储文件的磁盘或分区,或文件系统种类。因此,可以说"我有2个文件系统"意思是他有2个分区,一个存文件,或他用 "扩展文件系统",意思是文件系统的种类。
磁盘或分区和它所包括的文件系统的不同是很重要的。少数程序(包括最有理由的产生文件系统的程序)直接对磁盘或分区的原始扇区进行操作;这可能破坏一个存在的文件系统。大部分程序基于文件系统进行操作,在不同种文件系统上不能工作。
一个分区或磁盘能作为文件系统使用前,需要初始化,并将记录数据结构写到磁盘上。这个过程就叫建立文件系统。
大部分UNIX文件系统种类具有类似的通用结构,即使细节有些变化。其中心概念是超级块superblock, i节点inode, 数据块data block,目录块directory block, 和间接块indirection block。超级块包括文件系统的总体信息,比如大小(其准确信息依赖文件系统)。 i节点包括除了名字外的一个文件的所有信息,名字与i节点数目一起存在目录中,目录条目包括文件名和文件的i节点数目。 i节点包括几个数据块的数目,用于存储文件的数据。 i节点中只有少量数据块数的空间,如果需要更多,会动态分配指向数据块的指针空间。这些动态分配的块是间接块;为了找到数据块,这名字指出它必须先找到间接块的号码。
UNIX文件系统通常允许在文件中产生孔(hole) (用lseek ; 请看手册), 意思是文件系统假装文件中有一个特殊的位置只有0字节,但没有为这文件的这个位置保留实际的磁盘空间(这意味着这个文件将少用一些磁盘空间)。这对小的二进制文件经常发生,Linux共享库、一些数据库和其他一些特殊情况。 (孔由存储在间接块或i节点中的作为数据块地址的一个特殊值实现,这个特殊地址说明没有为文件的这个部分分配数据块,即,文件中有一个孔。)
孔有一定的用处。在笔者的系统中,一个简单的测量工具显示在200MB使用的磁盘空间中,由于孔,节约了大约4MB。在这个系统中,程序相对较少,没有数据库文件。
下面是文件系统的代码,根据这个代码我们可以更好地了解文件系统的工作流程
1. main.cpp
#include "head.h"
#include "blockinodesuperblock.h"
#include "initial.h"
#include "userop.h"
#include "file.h"
#include "dir.h"
#include "command.h"
#include "chsome.h"
// by ctu_85 http://blog.csdn.net/ctu_85/archive/2008/02/29/2135420.aspx
/////////////////////////////////////////////////////////////////////////////////////////
void main()
{
control.open("control.txt",ios::in | ios::out | ios::nocreate);
int i;
control>>i;
control.close();
if(i!=0)//不为0就初始化
{
initial();
}
control.open("control.txt",ios::in | ios::out | ios::nocreate);
control.seekp(0);
control<<0;//默认是上次基础上继续下去不用再初始化
control.close();
strcpy(curname,"root");//当前目录文件名为root
road[0]=0;//当前目录路径(存放从根目录到这里的结点号)
num=1;//最后位road[num-1]为当前目录文件i结点号
cout<<"请登陆系统
";
while( !login() )//登陆为止
cout<<"wrong !!!
";
cout<<" login success"<<endl;
cout<<"******Welcome "<<auser<<"******";
readsuper();
getcommand();//命令解析函数
writesuper();
}
2. blockinodesuperblock.h
/////////////////////////////////////////////////////////////////////////////////////////
int ialloc()//申请一个i结点 返回结点号 否则返回-1
{
if(superblock.fiptr>0)
{
int temp=superblock.fistack[80-superblock.fiptr];//当前可用
superblock.fistack[80-superblock.fiptr]=-1;
superblock.fiptr--;
return temp;
}
return -1;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
void ifree(int index)//指定一个结点号,回收一个i结点
{
disk.open("disk.txt",ios::in | ios::out | ios::nocreate );//清空结点
disk.seekp(514+64*index+2*(index/8));
disk<<setw(64)<<' ';
disk.close();
for(int i=80-superblock.fiptr;i<80;i++)//结点号找到合适位置插入空闲结点号栈
{
if(superblock.fistack<index)//小于它的前移一位
{
superblock.fistack[i-1]=superblock.fistack;
}
else//放在第一个大于它的结点号前面
{
superblock.fistack[i-1]=index;
break;
}
}
superblock.fiptr++;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/*成组链接法*/
int balloc()//申请一个盘块 返回盘块号 否则返回-1
{
int temp=superblock.fbstack[10-superblock.fbptr];
if(superblock.fbptr==1)//是栈底了==>是记录盘块了
{
//是最后记录盘块最后号0(保留作栈底 分配不成功)
if(temp==0)
{
return -1;
}
superblock.fbstack[10-superblock.fbptr]=-1;
superblock.fbptr=0;
//盘块内容读入栈
for(int i=0;i<10;i++)
{
int id,num=0;
disk.open("disk.txt",ios::in | ios::out | ios::nocreate );
//先计算盘块内容个数num(最多10),最后盘块可能不到10个
disk.seekg(514*temp);
for(int i=0;i<10;i++)
{
disk>>id;
num++;
if(id==0) break;
}
disk.seekg(514*temp);//盘块内容读入栈
for(int j=10-num;j<10;j++)
{
disk>>id;
superblock.fbstack[j]=id;
}
superblock.fbptr=num;
disk.close();
}
disk.open("disk.txt",ios::in | ios::out | ios::nocreate );//清空回收盘块
disk.seekp(514*temp);
disk<<setw(512)<<' ';
disk.close();
//盘块使用掉
return temp;
}
else//不是记录盘块==>盘块使用掉
{
superblock.fbstack[10-superblock.fbptr]=-1;
superblock.fbptr--;
return temp;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
FAT,FAT16,FAT32,NTFS,exFAT
通常PC机使用的文件系统是FAT16。像基于MS-DOS,Win 95等系统都采用了FAT16
文件系统。在Win 9X下,FAT16支持的分区最大为2GB。我们知道计算机将信息保存在硬盘上称为“簇”的区域内。使用的簇越小,保存信息的效率就越高。在FAT16的情况下,分区越大簇就相应的要大,存储效率就越低,势必造成存储空间的浪费。并且随着计算机硬件和应用的不断提高,FAT16文件系统已不能很好地适应系统的要求。在这种情况下,推出了增强的文件系统FAT32。同FAT16相比,FAT32主要具有以下特点:
1. 同FAT16相比FAT32最大的优点是可以支持的磁盘大小达到2TB(2047GB),但是不能支持小于512MB的分区。
*基于FAT32的Win 2000可以支持分区最大为32GB;而基于 FAT16的Win 2000支持的分区最大为4GB。
2. 由于采用了更小的簇,FAT32文件系统可以更有效率地保存信息。如两个分区大小都为2GB,一个分区采用了FAT16文件系统,另一个分区采用了FAT32文件系统。采用FAT16的分区的簇大小为32KB,而FAT32分区的簇只有4KB的大小。这样FAT32就比FAT16的存储效率要高很多,通常情况下可以提高15%。
3. FAT32文件系统可以重新定位根目录和使用FAT的备份副本。另外FAT32分区的启动记录被包含在一个含有关键数据的结构中,减少了计算机系统崩溃的可能性。
NTFS文件系统
NTFS文件系统是一个基于安全性的文件系统,是Windows NT所采用的独特的文件系统结构,它是建立在保护文件和目录数据基础上,同时照顾节省存储资源、减少磁盘占用量的一种先进的文件系统。使用非常广泛的
Windows NT 4.0采用的就是NTFS 4.0文件系统,相信它所带来的强大的系统安全性一定给广大用户留下了深刻的印象。Win 2000采用了更新版本的NTFS文件系统??NTFS 5.0,它的推出使得用户不但可以像Win 9X那样方便快捷地操作和管理计算机,同时也可享受到NTFS所带来的系统安全性。
NTFS 5.0的特点主要体现在以下几个方面:
1. NTFS可以支持的分区(如果采用动态磁盘则称为卷)大小可以达到2TB。而Win 2000中的FAT32支持分区的大小最大为32GB。
2. NTFS是一个可恢复的文件系统。在NTFS分区上用户很少需要运行磁盘修复程序。NTFS通过使用标准的事物处理日志和恢复技术来保证分区的一致性。发生系统失败事件时,NTFS使用日志文件和检查点信息自动恢复文件系统的一致性。
3. NTFS支持对分区、文件夹和文件的压缩。任何基于Windows的应用程序对NTFS分区上的压缩文件进行读写时不需要事先由其他程序进行解压缩,当对文件进行读取时,文件将自动进行解压缩;文件关闭或保存时会自动对文件进行压缩。
4. NTFS采用了更小的簇,可以更有效率地管理磁盘空间。在Win 2000的FAT32文件系统的情况下,分区大小在2GB~8GB时簇的大小为4KB;分区大小在8GB~16GB时簇的大小为8KB;分区大小在16GB~32GB时,簇的大小则达到了16KB。而Win 2000的NTFS文件系统,当分区的大小在2GB以下时,簇的大小都比相应的FAT32簇小;当分区的大小在2GB以上时(2GB~2TB),簇的大小都为4KB。相比之下,NTFS可以比FAT32更有效地管理磁盘空间,最大限
度地避免了磁盘空间的浪费。
5. 在NTFS分区上,可以为共享资源、文件夹以及文件设置访问许可权限。许可的设置包括两方面的内容:一是允许哪些组或用户对文件夹、文件和共享资源进行访问;二是获得访问许可的组或用户可以进行什么级别的访问。访问许可权限的设置不但适用于本地计算机的用户,同样也应用于通过网络的共享文件夹对文件进行访问的网络用户。与FAT32文件系统下对文件夹或文件进行访问相比,安全性要高得多。另外,在采用NTFS格式的Win 2000中,应用审核策略可以对文件夹、文件以及活动目录对象进行审核,审核结果记录在安全日志中,通过安全日志就可以查看哪些组或用户对文件夹、文件或活动目录对象进行了什么级别的操作,从而发现系统可能面临的非法访问,通过采取相应的措施,将这种安全隐患减到最低。这些在FAT32文件系统下,是不能实现的。
6. 在Win 2000的NTFS文件系统下可以进行磁盘配额管理。磁盘配额就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。设置磁盘配额后,可以对每一个用户的磁盘使用情况进行跟踪和控制,通过监测可以标识出超过配额报警阈值和配额限制的用户,从而采取相应的措施。磁盘配额管理功能的提供,使得管理员可以方便合理地为用户分配存储资源,避免由于磁盘空间使用的失控可能造成的系统崩溃,提高了系统的安全性。
7. NTFS使用一个“变更”日志来跟踪记录文件所发生的变更。
exFAT
(全称Extended File Allocation Table File System,扩展FAT,即扩展文件分配表)是Microsoft在Windows Embeded 5.0以上(包括Windows CE 5.0、6.0、Windows Mobile5、6、6.1)中引入的一种适合于闪存的文件系统,为了解决FAT32等不支持4G及其更大的文件而推出。对于闪存,NTFS文件系统不适合使用,exFAT更为适用。
相对FAT文件系统,exFAT有如下好处:
•增强了台式电脑与移动设备的互操作能力
•单文件大小最大可达16EB(2 305 843 009 213 693 952字节,就是(理论值,16×1024×1024TB),1TB=1024G)
•簇大小可高达32MB
•采用了剩余空间分配表,剩余空间分配性能改进
•同一目录下最大文件数可达65 536个
•支持访问控制
•支持TFAT
采用该文件系统的闪存盘不支持Windows Vista ReadyBoost。Windows Vista SP1支持该文件系统。
请注意:exFAT只是一个折中的方案,只为U盘而生。
现在超过4GB的U盘格式化时默认是NTFS分区,但是这种格式是很伤U盘的,因为NTFS分区是采用“日志式”的文件系统,需要记录详细的读写操作,肯定会比较伤闪盘芯片,因为要不断读写。
下面请看exFAT、NTFS、FAT分区的比较
FAT32 NTFS exFAT
操作系统 Win 95 OSR2之后 Win2000之后 Win CE 6/Vista SP1
最小扇区 512bytes 512bytes 512bytes
最大扇区 64KB 64KB 32768KB
最大单一文件 2bytes-4GB 受最大分割容量 16EB(理论值)
最大格式化容量 32GB、2TB 2TB 16EB(理论值)
档案数量 4194304 无 至少可以大于1000
[3]1.支持非常大的文件和存储设备
2.对性能的改进支持
3.对未来的创新的可扩展性功能的支持
Ext2文件系统
Ext2是 GNU/Linux 系统中标准的文件系统,其特点为存取文件的性能极好,对于中小型的文件更显示出优势,这主要得利于其簇快取层的优良设计。
其单一文件大小与文件系统本身的容量上限与文件系统本身的簇大小有关,在一般常见的 x86 电脑系统中,簇最大为 4KB, 则单一文件大小上限为 2048GB, 而文件系统的容量上限为 16384GB。
但由于目前核心 2.4 所能使用的单一分割区最大只有 2048GB,实际上能使用的文件系统容量最多也只有 2048GB。
至于Ext3文件系统,它属于一种日志文件系统,是对ext2系统的扩展。它兼容ext2,并且从ext2转换成ext3并不复杂。
Ext3文件系统Ext3是一种日志式文件系统,是对ext2系统的扩展,它兼容ext2。日志式文件系统的优越性在于:由于文件系统都有快取层参与运作,如不使用时必须将文件系统卸下,以便将快取层的资料写回磁盘中。因此每当系统要关机时,必须将其所有的文件系统全部shutdown后才能进行关机。
如果在文件系统尚未shutdown前就关机 (如停电) 时,下次重开机后会造成文件系统的资料不一致,故这时必须做文件系统的重整工作,将不一致与错误的地方修复。然而,此一重整的工作是相当耗时的,特别是容量大的文件系统,而且也不能百分之百保证所有的资料都不会流失。
为了克服此问题,使用所谓‘日志式文件系统 (Journal File System) ’。此类文件系统最大的特色是,它会将整个磁盘的写入动作完整记录在磁盘的某个区域上,以便有需要时可以回溯追踪。
由于资料的写入动作包含许多的细节,像是改变文件标头资料、搜寻磁盘可写入空间、一个个写入资料区段等等,每一个细节进行到一半若被中断,就会造成文件系统的不一致,因而需要重整。
然而,在日志式文件系统中,由于详细纪录了每个细节,故当在某个过程中被中断时,系统可以根据这些记录直接回溯并重整被中断的部分,而不必花时间去检查其他的部分,故重整的工作速度相当快,几乎不需要花时间。