使用B+树作为管理结构,但是为了可以容纳更多信息,做了一定的修改。下面是传统的B+树,信息全部保存在叶结点中,通过内部节点进行索引,每一个父级节点的元素索引一个子节点。
以下是经过修改的B+树,每个父节点可以多索引一个子节点。有利于进一步降低树的高度,容纳更多信息。
B+树的操作有插入、删除、节点分裂、节点合并、查找、遍历等。
下面是文件索引结构设计:
//B+树内部节点,52kb
#define BNODE_NUM 1401
#define BNODE_SIZE 52*1024
#define CHILD_TYPE_BNODE 0 //childType属性,内部节点类型
#define CHILD_TYPE_LNODE 3 //childType属性,叶节点类型
typedef struct BTreeNode {
extName name[BNODE_NUM]; //文件名描述符数组
uint32 child[BNODE_NUM + 1]; //子节点指针数组,可能为内部节点或叶节点,使用时,要强制转换为结点指针后使用
uint16 name_off[BNODE_NUM - 1]; //记录每个文件名的起始下标,从第二个文件名开始
uint32 parent; //父节点指针
uint16 name_off_num:14; //记录name_off数组的有效长度
uint16 childType:2; //子节点类型,0=内部节点,3=叶节点
uint16 namenum; //记录name数组的长度
}BTreeNode, * _btreenode, * _bn;
//B+树叶节点
#define LNODE_NUM 2409
//叶节点,80kb
#define LNODE_SIZE 80*1024
typedef struct LeafNode {
fileItems fi[LNODE_NUM]; //文件描述符数组
uint16 file_off[LNODE_NUM - 1]; //文件偏移数组,描述文件的起始描述符位下标,由于第一个文件项的下标肯定为0,因此从第二个文件描述符开始。
uint16 finum; //fi数组有效项的长度
uint16 file_off_num; //file_off数组有效项的数量
uint32 prev; //前驱节点
uint32 next; //后继节点
uint32 parent; //父节点指针
}LeafNode, * _leafnode, * _ln;
分为两种,一个是叶节点用来保存有关文件的信息,一个是内部节点,用来索引叶节点。由于文件信息需要的储存空间不同,因此在节点结构中设计了偏移数组,用于记录每一个信息元素的位置。由于增加了这些设计,使B+树在实现上也变得更加复杂。
lxfs保存文件信息的结构称为文件描述符。文件描述符的设计参考了FAT32,但是做了一定修改。如下
//文件属性/f分区属性
typedef struct {
byte dpl : 2; //文件权限;分区权限 0,1,2,3
byte extname : 1; //下一项描述符类型,=0,文件描述符;=1,扩展文件名描述符
byte isext : 1; //本描述符是否为扩展描述符,=1
byte data : 1; //=1文件正常,=0此文件可能存在问题;作为分区描述符时,=1说明此分区是系统分区,
byte en_folder : 1; //说明floder项有效,以此文件名作为后面文件的目录基准,同目录下的文件应该只有一个文件的此项为1
byte hide : 1; //=1隐藏文件;=1隐藏分区
byte del : 1; //=1已删除文件,相当于放入回收站,标记删除,为了保证可以恢复;=1分区删除
}fileAtt;
//文件日期结构
typedef struct {
uint32 s : 6; //秒
uint32 m : 6; //分
uint32 h : 5; //时
uint32 day : 5; //日
uint32 month : 4; //月
uint32 year : 6; //年,使用是将此值加上基准年份等于时间
}fDate, * _fdate;
//用于描述符文件信息的文件描述符
typedef struct {
byte ms : 7; //创建时间的10毫秒位,ms*10=大约的创建时间,现在感觉这项没什么用
byte dis : 1; //=0扩展文件名描述符,=1文件描述符,此项恒等于1
fileAtt fatt; //文件属性
char name[FTNAME_SIZE]; //文件名,占用6字节
fDate createDate; //创建日期
fDate lastVisitDate; //最后访问日期
fDate lastModifiedDate; //最后修改日期
uint32 size; //文件长度,单位4kb,因此一个文件最大为4096GB=4TB
uint32 position; //在分区内的偏移位置,单位4kb,最大检索16tb,因此一个分区的最大为16tb
uint16 offset : 12; //文件占用的最后一个4kb内的偏移
uint16 extnum : 4; //扩展描述符数量,最大为15个,当此值=15时,应当查看最后一个扩展描述符,确定是否还有扩展描述符
uint16 folder; //文件夹包含数量,如果fatt.en_folder=1,说明此文件描述符组为文件夹描述符,则folder包含了该文件夹的文件数量
}fileTable, * _filetable;
//用于储存文件名的文件名描述符
typedef struct extName {
byte size : 5; //本项文本串长度
byte ext : 1; //1=有扩展项,此项为了避免文件描述符指出的15项的限制,以期能够储存更多文件项
byte start : 1; //=1起始项,为扩展文件名描述符组的首项
byte dis : 1; //=0扩展文件名描述符,=1文件描述符,此项应该恒等于0
char name[31]; //文件名
}extName, * _extname;
//文件项联合体,一个文件项可能是文件描述符,也可能是扩展文件名描述项
typedef union {
fileTable ft; //文件描述符
extName en; //扩展文件名描述符
}fileItems, * _fileitems;
fileTable用于储存文件信息,32字节;
extName用于储存扩展文件名信息,32字节。
但是一个fileTable可能无法保存文件的所有信息,因此在现有设计中,设计了文件描述符组来储存信息。一个文件描述符组中描述符的数量是不定的,但是最高允许拥有16个fileTable和15个extName。第一个fileTable称为主文件描述符,记录当前组的描述符,记录其后属于同一组的描述符的数量。
另见:尝试做一个简单的文件系统_lindorx的博客-CSDN博客_一个简单的文件系统
github:GitHub - lindorx/lxfs: 一个小型的文件系统模拟程序,使用B+树作为主要数据结构
测试结果: