操作系统的一个课程设计,实现一个二级文件夹文件系统。

用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

用户文件文件夹地址

Peter

12345

3

Ben

Abc

5

表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

A

1

3

50

B

2

5

52

表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; }

本实验所有源代码请到我的  Github下载,也欢迎大家fork继续进行完好。

最新文章

  1. asp.net core 使用protobuf
  2. 设置 java -jar 的进程显示名称
  3. Ubuntu上安装mono并进行C#代码测试
  4. GTD_百度百科
  5. C++:构造函数默认的参数声明
  6. spring事物的传播行为
  7. 【HDOJ】1097 A hard puzzle
  8. nginx提示No input file specified怎么办
  9. C#调用R语言输出图片
  10. codeforces 653D. Delivery Bears 网络流
  11. lua 远程调试 【zeroBrane 使用mobdebug】(good转)
  12. DSP TMS320C6000基础学习(7)—— Bootloader与VectorTable
  13. js Date 日期格式化(转)
  14. 关于在VI中查看BIN文件二进制值不对的问题
  15. 三栏布局之 css3 calc和 flex
  16. 关于设计SQL表的一些问题
  17. 小乌龟 coding 克隆、提交一直提示无权限
  18. 20165303 魏煜第四次实验 Android开发
  19. DevExpress ASP.NET v18.2新功能详解(四)
  20. 各版本.NET委托的写法回顾(转)

热门文章

  1. [转]使用ThinkPHP框架快速开发网站(多图)
  2. CSS3悬浮动画效果
  3. Android:用签名打包后微信分享失效
  4. Android传递中文参数方法(之一)
  5. 忘记Oracle密码
  6. Showplan 逻辑运算符和物理运算符参考
  7. python 分割文件、组合文件
  8. 一款批量linux管理工具batchshell
  9. linux 汇编 - 函数调用
  10. mongodb分片集群安装教程