操作系统:二级文件夹文件系统的实现(cc++语言)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

操作系统:⼆级⽂件夹⽂件系统的实现(cc++语⾔)
操作系统的⼀个课程设计,实现⼀个⼆级⽂件夹⽂件系统。

⽤disk.txt模拟磁盘,使⽤Help查看⽀持的命令及其操作⽅式,root为超级⽤户(写在disk.txt中)
⽂件的逻辑结构:流式⽂件。

物理结构:链接⽂件。

物理空间管理:空暇链法。

⽂件夹结构:⼆级⽂件夹结构。

⽂件夹搜索技术:线性搜索。

FCB:含⽂件相关的所有属性。

物理盘块的设计(disk.txt)
以⼀个⽂本⽂件disk.txt模拟硬盘,设定硬盘容量分为100个物理块,每⼀个物理块的⼤⼩512字节(为了測试⽅便,最后68个数据块每⼀个的⼤⼩为256字节),盘块之间⽤(‘\n’)切割。

因此⼀个盘块:512字节数据+1字节(‘\n’)切割符=513字节。

则disk.txt 长度=51300(100×513)+1字节(⽂件结束符)=51301字节。

100块盘块的分布:
1#: MFD块,存放MFD信息;
2-17#: UFD块,存放UFD信息;
18-33#: UOF块,存放UOF信息;
其余物理块⽤于存放⽂件内容。

# MFD块的设计
硬盘的第1个物理块固定⽤于存放主⽂件⽂件夹MFD。

MFD结构例如以下:
typedef struct mfd{
username ;//username 14B
userpwd ;//password14B
link; //该⽤户的UFD所在的物理块号(4B)
}MFD;
每⼀个MFD项占32字节。

因此,1个物理块可存放512/32=16个MFD(⽤户),即本⽂件系统最多可管理16个⽤户。

例如以下表1所看到的:
username password⽤户⽂件⽂件夹地址
Peter123453
Ben Abc5
表1 ⽂件系统⽤户⽂件夹信息表
2#-17# UFD块的设计
2#-17#物理块:固定⽤于存放⽤户⽂件⽂件夹UFD。

假设⼀个⽤户须要⼀个UFD块。

因此,16个⽤户共须要16个UFD块。

UFD结构例如以下:
typedef struct {
filename //⽂件名称14B;
mode; ///⽂件权限0-readonly;1-writeonly;2-read/write
length; ///⽂件长度(以字节数计算)
addr;//该⽂件的第1个⽂件块对应的物理块号
}UFD;
⼀个UFD项设为32 Bytes。

⼀个块可存放16个UFD项。

则⼀个⽤户最多可创建16个⽂件。

例如以下表2所看到的:
Filename Mode Length Addr
A1350
B2552
表2 ⽤户⽂件⽂件夹信息表
18#-33# UOF块的设计
18#-33#物理块:固定⽤于存放主⽂件⽂件夹UOF,假定⼀个⽤户须要⼀个块存放UOF。

⼀个UOF项占32字节,则⼀个块可存放512/32=16个UOF,即⼀个⽤户可同⼀时候打开的⽂件数为16个。

⽤户已打开表”(UOF)。

⽤以说明⽤户当前正在使⽤⽂件的情况。

假设⽤户最多同⼀时候找开或建⽴16个⽂件。

则⽤户已打开⽂件表UOF应该有16个登记栏,结构例如以下表3所看到的:
⽂件名称⽂件属性状态(打开/建⽴)读指针写指针
应该为16个登记栏
表3 主⽂件⽂件夹信息表
⽤户请求打开或建⽴⼀个⽂件时。

对应的⽂件操作把有关该⽂件的信息登记到UOF中。

读指针和写打针⽤于指出对⽂件进⾏存取的对应位置。

34#-100# 数据块的设计
34#-100#:数据块(物理块每⼀个256字节),⽤于存放⽂件内容;为了实现物理块的分配和回收,程序始终维护⼀个空暇物理块表。

以物理块号从⼩到⼤排列。

物理块以链接分配⽅式,以最先适应法从空暇表中分配。

数据结构例如以下:
typedef struct cluster
{Num ;////物理块号
long nextcluster;/////指向下⼀物理块号
}Cluster;
主要结构分析清楚了之后,程序流程图就不在这⾥画了。

我使⽤的⼆维vector存储这些结构体,每次程序启动的时候先从⽂件⾥读取这些信息⾄内存,各种信息直接在内存中改动。

使⽤sysc指令将内存中的信息同步⾄disk.txt。

须要注意的⼏个问题:
(⼀)函数指针的运⽤
在众多对输⼊命令的函数处理中,假设採⽤if..else..或者switch..case..的⽅法势必会造成代码的冗余以及代码简洁度的缺失。

在这⾥我⽤到了函数指针的⽅法,定义⼀个结构体专门⽤于存储命令的字符串和对应的函数处理名称(函数指针),这样仅仅须要⼀次for循环遍历就能够简洁⾼效的处理这些命令,既体现了代码规范中的简洁⾼效的规则,⼜帮助⾃⼰深刻理解了C++语法中函数指针的应⽤。

typedef void(*func)(void);
typedef struct hand
{
char *pname;
func handler;
}HAND_TO;
HAND_TO handlerlist[] =
{
{ "Chmod", do_Chmod },
{ "Chown", do_Chown },
{ "Mv", do_Mv },
{ "Copy", do_Copy },
{ "Type", do_Type },
{ "Passwd", do_Passwd },
{ "Login", do_Login },
{ "Logout", do_Logout },
{ "Create", do_Create },
{ "Delete", do_Delete },
{ "Open", do_Open },
{ "Close", do_Close },
{ "Write", do_Write },
{ "Read", do_Read },
{ "Help", do_Help },
{ "dir", do_dir},
{ "sysc",do_sysc},
{ "Register", do_register},
{ "Exit", do_exit},
{ "Clear", do_Clear},
{ NULL, NULL }
};
(⼆)⽂件物理块的设计
在对⽂件内容的分块存储中。

由于UOF中仅仅记录了⽂件内容的起始物理块。

这对于写指针来说定位当前位置是能够实现的,由于我仅仅须要记录最后⼀个物理块的偏移量就可以。

追加写⼊的时候直接迭代到最后⼀个物理块进⾏写⼊。

可是对于读指针来说。

仅仅记录最后⼀个物理块的偏移量是不能够的,由于我上⼀次读的位置不⼀定位于⽂件的末尾,这样就会产⽣没有数据记录当前读的物理块的块号。

对此我的解决⽅法是读指针记录当前字节的总数,这样读指针/256能够得出当前的物理块的块号。

读指针%256能够得出当前读的物理块的偏移量。

问题得到了完美的解决。

void do_Write()
{
//Write filename buffer nbytes 写⽂件物理空间68
int is_ok = 0;
for (int i = 0; i < FileState[curID].size(); i++)
{
if (strcmp(FileState[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0)
{
is_ok = 1;
break;
}
}
if (is_ok == 0)
{
cout << "⽂件尚未打开!
" << endl;
return;
}
char buf[1024];
stringstream ss;
ss << cmd_in.cmd_num[3];
int temp;
ss >> temp;
for (int i = 0; i < FileInfo[curID].size(); i++)
{
if (strcmp(FileInfo[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0)
{
if (FileInfo[curID][i].mode == 1 || FileInfo[curID][i].mode == 2)//推断权限
{
break;
}
else
{
cout << "没有写的权限!" << endl;
return;
}
}
}
int index;
for (int i = 0; i < FileState[curID].size(); i++)
{
if (strcmp(FileState[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0)
{
index = i;
break;
}
}
//起始物理块
int address;
for (int i = 0; i < FileInfo[curID].size(); i++)
{
if (strcmp(FileInfo[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0)
{
address = FileInfo[curID][i].addr;
break;
}
}
//注意:此处发⽣了更改。

cout << "请输⼊buff的内容:" << endl;
gets(buf);
fflush(stdin);
//strcpy(buf, cmd_in.cmd_num[2].c_str());
int wbegin;
wbegin = FileState[curID][index].write_poit;
//找到写指针所在的最后⼀个磁盘
while (FileCluster[address].next_num != address)
address = FileCluster[address].next_num;
vector <int> newspace_num;//计算将要占⽤的物理块的数量
newspace_num.clear();
//int num = (256-wbegin+temp) / 256-1;
if (temp <= 256 - wbegin)
num = 0;
else
{
num = ceil((temp - (256 - wbegin))*1.0 / 256);
}
newspace_num.push_back(address);
//cout << newspace_num.size() << endl;//
for (int i = 0; i < FileCluster.size(); i++)
{
if (newspace_num.size() == num+1)
break;
if (FileCluster[i].is_data == 0)
{
newspace_num.push_back(i);
FileCluster[i].is_data = 1;
}
}
for (int k = 0; k < newspace_num.size() - 1; k++)
{
FileCluster[newspace_num[k]].next_num = newspace_num[k + 1]; }
for (int i = 0; i < temp; i++)
{
if (wbegin == 256)
{
wbegin = 0;
address = FileCluster[address].next_num;
}
FileCluster[address].data[wbegin] = buf[i];
wbegin++;
}
//更新写指针
FileState[curID][index].write_poit = wbegin;
cout << "磁盘写⼊成功!" << endl;
return;
}
本实验所有源代码请到我的下载,也欢迎⼤家fork继续进⾏完好。

相关文档
最新文档