虚拟磁盘管理系统的设计与开发
在Windows或者Linux下设计一个二级(或者树型)结构文件系统,要求至少实现以下功能:login 用户登录、dir 列出文件目录、create 创建文件、del 删除文件、open 打开文件、close 关闭文件、read 读文件、write 写文件、cd 进入子目录、rd 删除子目录、md 创建子目录等。
#include<iostream>
#include<cstring>
#include<string.h>
#include<cstdlib>
#include<Windows.h>
using namespace std;
const int M=1024*1024;//1M
const int K=1024;//1K
const int contentMaxSize=1024*128;
typedef struct DiskBlock{//文件分配表(FAT)中的磁盘块
int nextDiskBlock;//下一个磁盘块的地址
bool isFree;//当前磁盘块是否空闲
}DiskBlock;
const int FATSize=K*sizeof(DiskBlock);//FAT表中默认有1K个磁盘块
const int RootStart=FATSize/K+1;//根目录的起始盘块
typedef struct INodes{
struct INode{
char Name[10];//文件名
int Start;//文件的起始块的位置
int Size;//文件的长度
}INode[5];
int currentNumber;//当前打开文件的数目
}INodes;
typedef struct Catalog{
struct FCB{//文件控制块
char Name[10];//目录名
bool isCatelog;//是否为目录,true代表是目录,false代表是文件
int Size;//目录的盘块数,大小
int firstDisk;//起始盘块号
int Next;//子目录的起始盘块号
bool isRoot;//是否为根目录
}CatalogItem[7];
}Catalog;
DiskBlock *FAT;
Catalog *root;
Catalog *current;
INodes inode;//数据块
int id=-1;//数据块的序号
char *currentdir;//当前的路径名称
char *StartDisk;//虚拟磁盘的起始地址
void Interface(){
cout<<"|---------------------虚拟磁盘管理系统-----------------|"<<endl;
cout<<"|功能 操作|"<<endl;
cout<<"|创建子目录 mkdir|"<<endl;
cout<<"|打开指定目录 cd|"<<endl;
cout<<"|创建文件 create|"<<endl;
cout<<"|关闭文件 close|"<<endl;
cout<<"|打开文件 open|"<<endl;
cout<<"|写文件 write|"<<endl;
cout<<"|读文件 read|"<<endl;
cout<<"|列出文件目录 dir|"<<endl;
cout<<"|删除文件 del|"<<endl;
cout<<"|删除子目录 rmdir|"<<endl;
cout<<"|清屏 cls|"<<endl;
cout<<"|格式化虚拟磁盘 format|"<<endl;
cout<<"|保存并退出文件系统 exit|"<<endl;
cout<<"|------------------------------------------------------|"<<endl;
cout<<endl;
}
void format();
int openFile(char *name);
void InitFile(){
StartDisk=(char *)malloc(M*sizeof(char));
format();
}
void format(){
FILE *fp;
FAT=(DiskBlock*)(StartDisk+K);//FAT的地址
FAT[0].nextDiskBlock=-1;
FAT[0].isFree=true;
for(int i=1;i<RootStart-1;i++){
FAT[i].nextDiskBlock=i+1;
FAT[i].isFree=true;
}
FAT[RootStart].nextDiskBlock=-1;
FAT[RootStart].isFree=true;
for(int i=RootStart+1;i<K;i++){
FAT[i].nextDiskBlock=-1;
FAT[i].isFree=false;
}
root=(Catalog *)(StartDisk+FATSize+K);
//初始化目录
root->CatalogItem[0].isRoot=true;
root->CatalogItem[0].firstDisk=RootStart;
root->CatalogItem[0].Next=root->CatalogItem[0].firstDisk;
root->CatalogItem[0].isCatelog=true;
root->CatalogItem[0].Size=sizeof(Catalog);
strcpy(root->CatalogItem[0].Name,".");
root->CatalogItem[1].isRoot=true;
root->CatalogItem[1].firstDisk=RootStart;
root->CatalogItem[1].Next=root->CatalogItem[0].firstDisk;
root->CatalogItem[1].isCatelog=true;
root->CatalogItem[1].Size=sizeof(Catalog);
strcpy(root->CatalogItem[1].Name,"..");
if((fp=fopen("disk.dat","wb"))==NULL){
cout<<"Error:Cannot open file"<<endl;
return;
}
for(int i=2;i<7;i++){
root->CatalogItem[i].isRoot=false;
root->CatalogItem[i].firstDisk=-1;
root->CatalogItem[i].Next=-1;
root->CatalogItem[i].isCatelog=false;
root->CatalogItem[i].Size=0;
strcpy(root->CatalogItem[i].Name,"");
}
if((fp=fopen("disk.dat","wb"))==NULL){
cout<<"Error:Cannot open file!"<<endl;
return;
}
if(!fwrite(StartDisk,M,1,fp)){//总磁盘空间为1M,把虚拟磁盘空间保存到磁盘文件中去
cout<<"Error:File write error!"<<endl;
}
fclose(fp);
}
void enter(){
FILE *fp;
StartDisk=(char *)malloc(M*sizeof(char));
if((fp=fopen("disk.dat","rb"))==NULL){
cout<<"Error:Cannot open file!"<<endl;
return;
}
//将磁盘文件disk.dat读入虚拟磁盘空间内
if(!fread(StartDisk,M,1,fp)){
cout<<"Error:Cannot read file!"<<endl;
exit(0);
}
FAT=(DiskBlock *)(StartDisk+K);//FAT的地址
root=(Catalog *)(StartDisk+FATSize+K);//根目录地址
fclose(fp);
//初始化数据块
for(int i=0;i<5;i++){
strcpy(inode.INode[i].Name,"");
inode.INode[i].Start=-1;
inode.INode[i].Size=0;
}
current=root;//将当前目录设为根目录
currentdir=(char *)malloc(K*sizeof(char));
strcpy(currentdir,"Root:");
}
void show(){
cout<<endl<<currentdir<<">";
}
//退出文件系统
void exitSystem(){
FILE *fp;
if((fp=fopen("disk.dat","wb"))==NULL){
cout<<"Error:Cannot open file!"<<endl;
return;
}
if(!fwrite(StartDisk,M,1,fp)){//把虚拟磁盘空间保存到磁盘文件中去
cout<<"Error:File write error!"<<endl;
}
fclose(fp);
free(StartDisk);
free(currentdir);
cout<<"Exit successful"<<endl;
return;
}
//创建文件
bool createFile(char *name){
bool flag=false;
int temp1,temp2;
//文件名过长
if(strlen(name)>8){
cout<<"Error:The file name is too long!"<<endl;
return false;
}
for(int i=2;i<7;i++){
if(!strcmp(current->CatalogItem[i].Name,name)){
flag=true;
break;
}
}
if(flag){
cout<<"Error:The file name already exists!"<<endl;
return false;
}
flag=false;
for(int i=2;i<7;i++){
if(current->CatalogItem[i].firstDisk==-1){
temp1=i;
flag=true;
break;
}
}
if(!flag){
cout<<"Error:Empty directory entry not found"<<endl;
return false;
}
if(inode.currentNumber>=5){
cout<<"Error:Too many files open"<<endl;
return false;
}
flag=false;
for(int i=RootStart+1;i<K;i++){
if(!FAT[i].isFree){
flag=true;
temp2=i;
}
}
if(!flag){
cout<<"Error:There are no idle memory blocks"<<endl;
return false;
}
FAT[temp2].isFree=true;//分配空闲块
strcpy(current->CatalogItem[temp1].Name,name);
current->CatalogItem[temp1].firstDisk=temp2;
current->CatalogItem[temp1].Size=0;
current->CatalogItem[temp1].Next=temp2;
current->CatalogItem[temp1].isCatelog=false;
return true;
}
//打开文件
int openFile(char *name){
bool flag=false;
int temp1,temp2;
for(int i=2;i<7;i++){
if(!strcmp(current->CatalogItem[i].Name,name)){
flag=true;
temp1=i;
break;
}
}
if(!flag){
return -1;
}
if(current->CatalogItem[temp1].isCatelog){
return -2;
}
flag=false;
for(int i=0;i<5;i++){
if(!strcmp(inode.INode[i].Name,name)){
flag=true;
}
}
if(flag){
return -3;
}
if(inode.currentNumber>=5){
return -4;
}
for(int i=0;i<5;i++){
if(inode.INode[i].Start==-1){
temp2=i;
break;
}
}
inode.INode[temp2].Start=current->CatalogItem[temp1].firstDisk;
strcpy(inode.INode[temp2].Name,name);
inode.INode[temp2].Size=current->CatalogItem[temp1].Size;
inode.currentNumber++;
return temp2;
}
//关闭文件
int closeFile(char *name){
int temp;
bool flag=false;
for(int i=0;i<5;i++){
if(!strcmp(inode.INode[i].Name,name)){
temp=i;
flag=true;
}
}
if(!flag){
return -1;
}
strcpy(inode.INode[temp].Name,"");
inode.INode[temp].Start=-1;
inode.INode[temp].Size=0;
inode.currentNumber--;
return 0;
}
//写文件
bool writeFile(int fd,char *buf,int len){
char *first;
int item,temp,i,j,len1,len2,modlen;
char Space=' ';
char Enter='\n';
//$代表空格,#代表回车
for(int i=0;i<len;i++){
if(buf[i]=='$') buf[i]=Space;
else if(buf[i]=='#') buf[i]=Enter;
}
item=inode.INode[fd].Start;//读取文件打开表的第一个盘块号
//找到当前目录对应表项的序号
for(i=2;i<7;i++){
if(current->CatalogItem[i].firstDisk==item){
temp=i;
break;
}
}
while(FAT[item].nextDiskBlock!=-1){
item=FAT[item].nextDiskBlock;
}
//计算出该文件的尾地址
first= StartDisk+item*K+inode.INode[fd].Size%K;
if(K-inode.INode[fd].Size%K>len){
strcpy(first,buf);
inode.INode[fd].Size=inode.INode[fd].Size+len;
current->CatalogItem[temp].Size=current->CatalogItem[temp].Size+len;
}else{
for(i=0;i<(K-inode.INode[fd].Size%K);i++){
//在最后一块的磁盘块的剩余地址写一部分内容
first[i]=buf[i];
}
len1=len-(K-inode.INode[fd].Size%K);
len2=len1/K;
modlen=len1%K;
if(modlen>0){
len2++;//所需的磁盘块
}
for(j=0;j<len2;j++){
for(i=RootStart+1;i<K;i++){
if(FAT[i].isFree==false) break;
}
if(i>=K){
cout<<"Error:There is no memory!"<<endl;
return false;
}
first=StartDisk+i*K;
//最后要分配的一块空间
if(j==len2-1){
for(int k=0;k<len-(K-inode.INode[fd].Size%K)-j*K;k++){
first[k]=buf[k];
}
}else{
for(int k=0;k<K;k++){
first[k]=buf[k];
}
}
FAT[item].nextDiskBlock=i;//找到一块后将它的序号放在上一块的指针中
FAT[i].isFree=true;
FAT[i].nextDiskBlock=-1;//没有下一块
}
inode.INode[fd].Size=inode.INode[fd].Size+len;
current->CatalogItem[temp].Size=current->CatalogItem[temp].Size+len;
}
return true;
}
//读文件
bool readFile(int fd,char *buf){
int len=inode.INode[fd].Size;
char *first;
int i,j,item;
int len1,modlen;
item=inode.INode[fd].Start;
len1=len/K;
modlen=len%K;
if(modlen!=0) len1++;
first=StartDisk+item*K;//计算文件的起始位置
for(i=0;i<len1;i++){
if(i==len1-1){
for(j=0;j<len-i*K;j++){
buf[i*K+j]=first[j];
}
}else{
for(j=0;j<len-i*K;j++){
buf[i*K+j]=first[j];
}
item=FAT[item].nextDiskBlock;
first=StartDisk+item*K;
}
}
return true;
}
//删除文件
int delFile(char *name){
bool flag=false;
int temp,temp2;
for(int i=2;i<7;i++){
if(!strcmp(current->CatalogItem[i].Name,name)){
flag=true;
temp=i;
break;
}
}
if(!flag){
return -1;
}
if(current->CatalogItem[temp].isCatelog) return -3;//如果删除的是目录
//要删除的文件不能正在打开
for(int i=0;i<5;i++){
if(!strcmp(inode.INode[i].Name,name)) return -2;
}
int item=current->CatalogItem[temp].firstDisk;
while(item!=-1){
temp2=FAT[item].nextDiskBlock;
FAT[item].nextDiskBlock=-1;
FAT[item].isFree=false;
item=temp2;
}
current->CatalogItem[temp].firstDisk=-1;;
current->CatalogItem[temp].Next=-1;
current->CatalogItem[temp].isCatelog=false;
current->CatalogItem[temp].Size=0;
current->CatalogItem[temp].isRoot=false;
strcpy(current->CatalogItem[temp].Name,"");
strcpy(inode.INode[temp].Name,"");
return 0;
}
//显示当前子目录
void dir(){
for(int i=2;i<7;i++){
if(current->CatalogItem[i].firstDisk!=-1){
cout<<current->CatalogItem[i].Name<<"\t";
if(!current->CatalogItem[i].isCatelog) cout<<"<File>"<<endl;
else cout<<"<Catalogue>"<<endl;
}
}
}
int mkdir(char *name){
Catalog *curMkdir;
bool flag=false;
int temp1,temp2;
if(!strcmp(name,".")){
return -4;
}
if(!strcmp(name,"..")){
return -4;
}
if(strlen(name)>8){
return -1;
}
for(int i=2;i<7;i++){
if(current->CatalogItem[i].firstDisk==-1){
flag=true;
temp1=i;
break;
}
}
//根目录已经存满了
if(!flag) return -2;
flag=false;
for(int i=2;i<7;i++){
if(!strcmp(current->CatalogItem[i].Name,name)){
flag=true;
break;
}
}
//出现重名的文件目录
if(flag) return -3;
flag=false;
//寻找空闲的磁盘块
for(int i=RootStart+1;i<K;i++){
if(!FAT[i].isFree){
flag=true;
temp2=i;
break;
}
}
if(!flag) return -5;
FAT[temp2].isFree=true;
//填写目录项
strcpy(current->CatalogItem[temp1].Name,name);
current->CatalogItem[temp1].firstDisk=temp2;
current->CatalogItem[temp1].Size=sizeof(Catalog);
current->CatalogItem[temp1].Next=temp2;
current->CatalogItem[temp1].isCatelog=true;
curMkdir=(struct Catalog*)(StartDisk+current->CatalogItem[temp1].firstDisk*K);
//初始化目录
curMkdir->CatalogItem[0].isRoot=false;
curMkdir->CatalogItem[0].firstDisk=current->CatalogItem[temp1].firstDisk;
curMkdir->CatalogItem[0].Next=curMkdir->CatalogItem[0].firstDisk;
curMkdir->CatalogItem[0].isCatelog=true;
curMkdir->CatalogItem[0].Size=sizeof(Catalog);
strcpy(curMkdir->CatalogItem[0].Name,".");
curMkdir->CatalogItem[1].isRoot=false;
curMkdir->CatalogItem[1].firstDisk=current->CatalogItem[0].firstDisk;
curMkdir->CatalogItem[1].Next=curMkdir->CatalogItem[1].firstDisk;
curMkdir->CatalogItem[1].isCatelog=true;
curMkdir->CatalogItem[1].Size=sizeof(Catalog);
strcpy(curMkdir->CatalogItem[1].Name,"..");
for(int i=2;i<7;i++){
curMkdir->CatalogItem[i].isRoot=false;
curMkdir->CatalogItem[i].firstDisk=-1;
curMkdir->CatalogItem[i].Next=-1;
curMkdir->CatalogItem[i].isCatelog=false;
curMkdir->CatalogItem[i].Size=0;
strcpy(curMkdir->CatalogItem[i].Name,"");
}
return 0;
}
int rmdir(char *name){
Catalog *tempDir;
int temp,item;
bool flag=false;
for(int i=2;i<7;i++){
if(!strcmp(current->CatalogItem[i].Name,name)){
flag=true;
temp=i;
break;
}
}
//不存在这个文件或目录
if(!flag) return -1;
//删除的不是目录
if(!current->CatalogItem[temp].isCatelog) return -3;
tempDir=(struct Catalog*)(StartDisk+current->CatalogItem[temp].Next*K);
flag=false;
for(int i=2;i<7;i++){
if(tempDir->CatalogItem[i].Next!=-1){
flag=true;
break;
}
}
if(flag) return -2;
item=current->CatalogItem[temp].firstDisk;
FAT[item].isFree=false;
current->CatalogItem[temp].isRoot=false;
current->CatalogItem[temp].firstDisk=-1;
current->CatalogItem[temp].Next=-1;
current->CatalogItem[temp].isCatelog=false;
current->CatalogItem[temp].Size=0;
strcpy(current->CatalogItem[temp].Name,"");
return 0;
}
int cd(char *name){
char *temp,*point,*point1;
int i,j,item;
Catalog *tempDir=current;
char *str=name;
if(!strcmp("\\",name)){
current=root;
strcpy(currentdir,"Root:");
return 0;
}
temp=(char *)malloc(K*sizeof(char));
for(i=0;i<(int)strlen(str);i++){
temp[i]=str[i];
}
temp[i]='\0';
for(j=0;j<7;j++){
if(!strcmp(tempDir->CatalogItem[j].Name,temp)) break;
}
free(temp);
//不在当前的目录
if(j>=7) return -1;
//打开的不是目录
if(!tempDir->CatalogItem[j].isCatelog) return -2;
item=tempDir->CatalogItem[j].firstDisk;
tempDir=(struct Catalog*)(StartDisk+item*K);
if(!strcmp("..",name)){
if(!current->CatalogItem[j-1].isRoot){
point=strchr(currentdir,'\\');//查找第一次出现\的位置
while(point!=NULL){
point1=point+1;//减去\所占的空间
point=strchr(point1,'\\');
}
*(point1-1)='\0';//将上一层的目录删掉
}
}else{
//修改当前目录
currentdir=strcat(currentdir,"\\");
currentdir=strcat(currentdir,name);
}
current=tempDir;
return 0;
}
int main(){
SetConsoleTitle("管理员:虚拟磁盘管理系统");
FILE *fp;
char *content=(char *)malloc(contentMaxSize*sizeof(char));
string operation[13];
operation[0]="exit";
operation[1]="create";
operation[2]="open";
operation[3]="close";
operation[4]="write";
operation[5]="read";
operation[6]="del";
operation[7]="mkdir";
operation[8]="rmdir";
operation[9]="dir";
operation[10]="cd";
operation[11]="format";
operation[12]="cls";
if((fp=fopen("disk.dat","rb"))==NULL){
InitFile();
}
enter();
//Interface();
show();
while(true){
string s;
char name[20],c;
int i;
bool flag=false;
bool flag1;
int temp;
cin>>s;
for(i=0;i<13;i++){
if(s==operation[i]){
flag=true;
break;
}
}
switch(i){
case 0:
free(content);
exitSystem();
return 0;
case 1:
cin>>name;
flag1=createFile(name);
if(flag1){
cout<<"File created successfully"<<endl;
}
show();
break;
case 2:
cin>>name;
id=openFile(name);
if(id==-1){
cout<<"Error:Cannot find file!"<<endl;
}else if(id==-2){
cout<<"Error:This is a directory and cannot be read or written!"<<endl;
}else if(id==-3){
cout<<"Error:File already open!"<<endl;
}else if(id==-4){
cout<<"Error:Too many open files!"<<endl;
}else{
cout<<"File opened successfully"<<endl;
}
show();
break;
case 3:
cin>>name;
temp=closeFile(name);
if(temp==-1){
cout<<"Error:The file was not opened!"<<endl;
}else{
cout<<"File closed successfully"<<endl;
}
show();
break;
case 4:
if(id==-1){
cout<<"Error:The file is not open!"<<endl;
}else{
cout<<"Please input the content of the file: ";
cin>>content;
flag1=writeFile(id,content,strlen(content));
if(flag1){
cout<<"The file was written successfully"<<endl;
}
}
show();
break;
case 5:
if(id==-1){
cout<<"Error:The file is not open!"<<endl;
} else{
flag1=readFile(id,content);
if(flag1){
for(int i=0;i<inode.INode[id].Size;i++){
cout<<content[i];
}
cout<<endl;
}
}
show();
break;
case 6:
cin>>name;
temp=delFile(name);
if(temp==-1){
cout<<"Error:File does not exist!"<<endl;
}else if(temp==-2){
cout<<"Error:The file is being opened. Please close the file first!"<<endl;
}else if(temp==-3){
cout<<"Error:You are not deleting a file!"<<endl;
}else{
cout<<"File deleted successfully"<<endl;
}
show();
break;
case 7:
cin>>name;
temp=mkdir(name);
if(temp==-1){
cout<<"Error:The file directory name is too long!"<<endl;
}else if(temp==-2){
cout<<"Error:The file directory is full!"<<endl;
}else if(temp==-3){
cout<<"Error:Directory name already exists!"<<endl;
}else if(temp==-4){
cout<<"Error:Directory name cannot be '. And'.. '!"<<endl;
}else if(temp==-5){
cout<<"Error:There is no more disk space!"<<endl;
}else{
cout<<"Folder created successfully"<<endl;
}
show();
break;
case 8:
cin>>name;
temp=rmdir(name);
if(temp==-1){
cout<<"Error:The file directory does not exist!"<<endl;
}else if(temp==-2){
cout<<"Error:Please delete its child file first!"<<endl;
}else if(temp==-3){
cout<<"Error:You are not deleting a file directory!"<<endl;
}else{
cout<<"Folder deleted successfully"<<endl;
}
show();
break;
case 9:
dir();
show();
break;
case 10:
cin>>name;
temp=cd(name);
if(temp==-1){
cout<<"Error:The directory is incorrect!"<<endl;
}else if(temp==-2){
cout<<"Error:You are not opening a directory!"<<endl;
}
show();
break;
case 11:
cout<<"Are you sure you want to format the virtual disk?(Y/N) ";
cin>>c;
if(c=='Y'||c=='y') {
format();
enter();
}
show();
break;
case 12:
system("cls");
//Interface();
show();
break;
default:
cout<<"Error:Wrong command input!"<<endl;
show();
break;
}
}
return 0;
}

浙公网安备 33010602011771号