虚拟磁盘管理系统的设计与开发

在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;
}
posted @ 2021-07-09 23:00  小布丁超级帅  阅读(191)  评论(0)    收藏  举报