操作系统课程设计报告(文件系统)

1.引言

随着计算机技术的快速发展,在计算机操作系统中,如何优化任务处理效率成为一大难题。通过一个简单多用户文件系统设计,加深对文件系统的理解及内部实现。运用多线程的调度尽可能的优化其效率,解决实际问题。

1.1任务要求

B类:用java语言模仿“生产者——消费者”问题
1.通过Java语言中的wait()和notify()命令模拟操作系统中的P/V操作;
2.为每个生产者/消费者产生一个线程,设计正确的同步算法
3.每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的 当前全部内容、当前指针位置和生产者/消费者线程的自定义标识符。
4.生产者和消费者各有两个以上。
5.多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。

C类:文件系统
设计一个多用户文件系统,理解文件系统的层次结构,完成基本的文件系统create、open、close、read/write等基本功能,并实现文件保护操作。实现以此为基础加入自己设计功能的小型文件系统 。

需要解决的问题:
1.如何让生产者在缓冲区满时不加数据。
2.如何让消费者在缓冲区空时不取数据。
3.如何使多个生产者或消费者线程的处理不发生冲突。
4.如何实现对文件系统的保护。
1.2选题
B类:用java语言模仿“生产者——消费者”问题;
C类:文件系统

当前发展概述

所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务。在运行池中,会有多个处于就绪状态的线程在等待CPU,JAVA虚拟机的一项任务就是负责线程的调度,线程调度是指按照特定机制为多个线程分配CPU的使用权。Java虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。
文件系统是操作系统用于明确存储设备或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性。从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。

可行性分析

对于运用Java语言模仿“生产者——消费者”问题,以及在Java虚拟机上的线程调度问题,以前学习过Java基础语法,掌握了Java中wait(),notify()等线程处理的方法。
对于设计多用户文件系统问题,小文件的高度并发访问性能低。当前很多服务不仅需要大量的大文件访问,而且需要小文件的并发访问。文件系统在访问一个文件时需要多次读写和多次网络来回,因此对低延迟的要求难度较高,需要深入钻研。

选题意义

在Java虚拟机上,通过运用Java语言模仿“生产者——消费者”问题,可以进一步加深我们对多线程方面知识的理解。这不仅可以巩固以前java所学的知识,还能进一步打好有关线程知识的基础。
通过设计一个多用户的“文件系统”,从中我们能更深理解文件系统的层次结构和内部实现,并可以熟悉文件系统create、open、close、read/write等基本操作,实现文件保护的同时,运用操作系统的所学知识加入自己设计的操作系统,由此实现对文件系统的创新。

2.需求分析与设计

2.1 需求分析

“生产者消费者”问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者/消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步;(2)在生产者和消费者之间建立一个管道。第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式。第二种管道缓冲区不易控制,被传输数据对象不易于封装等,实用性不强。
同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持。在Java中一共有五种方法支持同步,其中前四个是同步方法,一个是管道方法。
1.wait() / notify()方法
2.await() / signal()方法
3.BlockingQueue阻塞队列方法
4.Semaphore方法
5.PipedInputStream / PipedOutputStream
生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况:
在这里插入图片描述
存储空间已满,而生产者占用着它,消费者等着生产者让出空间从而去除产品,生产者等着消费者消费产品,从而向空间中添加产品。互相等待,从而发生死锁。
要实现多用户文件系统,首先要实现Login用户登录,必须登录成功才能进入文件系统进行相应操作,进入后,通过树状展示文件目录,右侧显示文件夹图标或这文件图标,选中节点鼠标右键弹出菜单,有新建目录,新建文件,删除文件,打开文件,修改文件,并分别实现其功能。

2.2系统框架和流程

“生产者”与”消费者”问题流程图:
在这里插入图片描述
文件系统流程图:
在这里插入图片描述
用户登录模块:
在这里插入图片描述

新建文件模块:
在这里插入图片描述

修改文件模块:

在这里插入图片描述

删除文件模块:
在这里插入图片描述

2.3 系统流程和模块描述
本系统为多用户的文件系统,因为是多用户使用,所以具备登录系统,注册用户的功能,各个用户之间的文件系统互不干扰,同时又要实现对文件增删改查的功能。采用二级目录,第一级为用户账号,第二级对应用户账号下的文件。
系统采用结构体存储用户,文件目录等内容。
系统大致为一个二级文件系统,可以实现以下几个功能::login(用户登录)、view(查看文件内容)、create(新建文件)、delete(删除文件)、modify(修改文件)、dir(列文件目录)。

用户登录模块:
首先,刚进入系统,还不会有文件系统,显示用户登录模块。系统分区后,系统初始化要完成文件系统的建立。验证用户的身份,输入用户名和密码,登录成功后会初始化当前用户文件系统中的信息。如果用户没有通过身份验证,则提示登录失败,退出系统。

创建文件模块:
在用户登录后才具有的功能,查找一个未使用的文件块用来存放用户的文件信息,构建一个文件系统的元素放入找到的文件块中。新建文件时要求输入文件名称,当文件名称不与已存在的文件目录中名称冲突时,同时文件不发生越界,则文件创建成功。

删除文件模块:
在文件目录中选中要删除的文件,若文件存在则继续判断文件是否被锁定。如果文件正使用处于锁定状态则删除失败。若处于非锁定状态,则删除成功。

查看文件模块:
首先要接受查看文件的名称,查询文件是否存在,如果不存在,则无法查看文件。若文件存在,则创建查看文件的结点并复制文件信息,即可查看到用户文件的数据部分,将数据显示到界面。

3.数据结构

文件系统数据结构:

typedef struct UFD		//存储文件信息
{
	char name[10];		//文件名
	int attribute;		//属性
	int length;			//长度
	int a[10];		//为文件本身分配10个空间
	int *p1;			//一级索引,100个空间
	int (*p2)[100];		//二级索引,100*100个空间
	struct UFD *next;
}UFD;
typedef struct DIR		//存储目录信息
{
	DIR* above;			//上一结点
	char name[10];
	int length;
	DIR *next;			//下一结点
	UFD *File_head;		//此目录下的文件指针
	DIR *Dir_head;		//此目录下目录链表指针
}DIR;
class  test			//定义管理用户目录的类
{
	DIR *now;			//当前目录
	UFD *Fhead;			//文件的头结点
	DIR *Dhead;			//根目录的目录链头结点
	char code[10];		//密码
	char name[10];		//用户名
	int length;			//用户空间大小
	int status;			//是否获得空间
public:
	void set_status(int);
	int dele_user();
	int dis_file();		//显示文件所占外存块号
	int dis_dir(DIR *d);//当前路径
	int get_length();
	char const *get_name();
	char const *get_code();
	int get_status();
	int set_user(char *,char *);//设置用户名与密码
	DIR *get_now();
	int dele_file(UFD *f);		//删除文件
	int dele_dir(DIR*);			//删除目录
	Test();						//构造
	~test();					//析构
	int goback();				//返回上级
	int dis_now();				//显示当前目录
	int new_file();
	int new_dir();
	int open_dir();
	int open_file();
	int first_dele_file();		//删除文件的前部分工作
	int first_dele_dir();		//删除目录的前部分工作
	int set_code();
};
class Cdisk{					//用户类
public:
	Test user[5];		//用户个数最多为5
	char code[10];
	int dis_disk();
	int first_dele_user();
	int dele_user(int);
	int new_user();				//查看当前用户与外存空间使用情况,后创建新用户
	int set_code();				//设置新密码
	int login(char);				//登陆
	Cdisk();
	virtual~Cdisk();			//虚函数,析构
};

4.关键技术

Java实现生产者与消费者问题:
生产者消费者问题,描述一组生产者向一组消费者提供产品信息。它们会共享一个有界的缓冲区,生产者向其放入产品信息,消费者从中取出产品信息。只要当前缓冲区未满,生产者就可放入产品消息,只要缓冲区中存有数据,消费者便可提取。
应满足以下两个同步条件:
1.仅仅在有缓冲池中至少有一个缓冲区已存入消息后,消费者才从中提取消息,否则消费者必须要等待。
2.仅仅有缓冲池至少有一个缓冲区为空,生产者才能将消息放入缓冲区,否则生产者必须等待。
使用
1.创建生产者,负责生产产品信息
在这里插入图片描述
2.创建消费者,负责消费信息
在这里插入图片描述
3.消费者类
在这里插入图片描述
4.生产者类

在这里插入图片描述
5.核心代码

public class ProductiveConsumption {
   private int front=0; //队头
    private  int next=0; //队尾
    private  int bufferLength;    //缓冲区大小
    private String buffer[];   //缓冲区
    private int emptyNum;
    public ProductiveConsumption(int bufferLength){
        this.bufferLength=bufferLength;
        buffer=new String[bufferLength];
        emptyNum=bufferLength;
    }
    //生产
    public  synchronized  void produce(String data){
        System.out.println("生产前,空缓冲区数目-----------"+emptyNum);
        System.out.println("***生产者正在生产"+data);
        while(full()){
            System.out.println("*****缓冲池已满,生产等待");
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notify();
        buffer[next]=data;
        next=(next+1)%bufferLength;
        System.out.println("****生产者成功生产:"+data);
        emptyNum--;
        System.out.println("生产后,空缓冲区数目-----------"+emptyNum);
    }
    //消费
    public synchronized  void consum(){
        System.out.println("消费前,空缓冲区数目-----------"+emptyNum);
        while (empty()){
            System.out.println("*****缓冲池为空,消费等待");
            try{
                this.wait();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("***消费者正在消费"+buffer[front]);
        this.notify();
        System.out.println("****消费者成功消费:"+buffer[front]);
        front=(front+1)%bufferLength;
        emptyNum++;
        System.out.println("消费后,空缓冲区数目-----------"+emptyNum);
    }
    //缓冲区是否已满
    public boolean full(){
        if(emptyNum==0){
            return  true;
        }
        return  false;
    }
    //缓冲区是否为空
    public boolean empty(){
        if(bufferLength==emptyNum){
            return true;
        }
        return false;
    }

}

使用synchronized对存储加锁,然后用objec原生的wait()和notify()做同步。通过加锁,限制同一时刻只能有一个读或写。
Wait()方法:当缓冲区已满或空时,生产者/消费者线程就会停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。
Notify()方法:但生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
6.测试类

文件系统:
空闲空间管理采用位示图法,文件目录采用多级目录使用,采用索引节点结构。
功能模块
1.创建文件

p=new UFD;   //首先开辟一个新的文件结构体
在根目录链中检查判断文件是否重名
cout<<"请输入建立的文件名:";
	cin>>p->name;
	if(now==0)			//根目录下的文件链
		f=Fhead;
	else				//当前目录下的文件链
		f=now->File_head;
	while(f!=0)			//检查是否文件重名
	{
		if(!strcmp(p->name,f->name))
		{
			cout<<"此文件已存在!"<<endl;
			return 0;	//退出
		}
		f=f->next;
	}
若空间不足,则无法执行创建操作:
if(p->length>disk_empty)		//空间不足
	{
		cout<<"文件太大,空间不足,当前空间为:"<<disk_empty<<endl;
		delete p;
		return 0;
	}
若空间剩余,则通过位示图法为其分配空间:
	disk_empty=disk_empty-p->length;	//剩余空闲盘块
	//
	for(i=0;i<p->length&&i<10;i++)		//文件较小时,直接地址,文件数据盘块号
		for(j;j<10000;j++)				//位示图法
			if(disk_block[j]==0)		//空闲
			{
				p->a[i]=j;				//得到此空间
				disk_block[j]=1;		//标记为已分配出去
				j++;
				break;					//跳出寻找,为文件分配下一空间
			}

2.删除文件

int test::first_dele_file()	//删除文件的前面工作
{
	char temp[10],a[5];
	cout<<"你要删除的文件名:"<<endl;
	cin>>temp;
	UFD *f=Fhead;	//数据文件头指针
	UFD *above=0;
	if(now!=0)
		f=now->File_head;	//当前目录下的数据文件
	while(f!=0)
	{
		if(!strcmp(f->name,temp))
			break;	//找到,跳出
		above=f;	//标记第一个文件
		f=f->next;
	}
	if(f==0)
	{
		cout<<"此文件不存在"<<endl;
		return 0;
	}
	cout<<"确定删除"<<f->name<<"文件吗?按0确定,其他键取消"<<endl;
	cin>>a;
	if(a[0]!='0')
	{
		cout<<"已取消删除文件。"<<endl;
		return 0;
	}
	disk_empty+=f->length;	//回收此数据文件的空间大小
	if(now==0)	//根目录
	{
		if(f==Fhead)
			Fhead=Fhead->next;
		else
			above->next=f->next;
	}
	else
	{
		DIR *d=now;
		while(d!=0)
		{
			d->length=f->length;
			d=d->above;
		}
		if(f==now->File_head)
			now->File_head=now->File_head->next;
		else
			above->next=f->next;
	}
	length-=f->length;
	this->dele_file(f);
	cout<<"删除成功"<<endl;
	return 1;
}
 
int test::dele_file(UFD *f)	//具体实现删除文件
{
	int i=0,m;
	for(i=0;i<10&&i<f->length;i++)	//回收文件具体空间,重置空闲
	{
		m=f->a[i];
		disk_block[m]=0;
	}
	if(f->p1!=0)	//回收一级索引
	{
		for(i=10;i<110&&i<f->length;i++)
		{
			m=f->p1[i-10];
			disk_block[m]=0;
		}
		delete[](f->p1);
	}
	if(f->p2!=0)	//回收二级索引
	{
		for(i=110;i<f->length;i++)
		{
			m=(f->p2)[(i-110)/100][(i-110)%100];
			disk_block[m]=0;
		}
		delete[](f->p2);
		delete f;
	}
	f=0;	//要删除的文件为空了
	return 1;
}

3.打开文件:

UFD *f=Fhead;	//文件头指针
	if(now!=0)
		f=now->File_head;	//指向文件
	while(f!=0)
	{
		if(!strcmp(f->name,n))
		{
			cout<<"文件打开成功"<<endl;
			return 1;
		}
		f=f->next;
	}
	cout<<"当前目录无此文件"<<endl;

4.显示当前目录:

int test::dis_now()	//显示当前目录
{
	DIR *d=Dhead;
	UFD *f=Fhead;
	if(now!=0)
	{
		d=now->Dir_head;	//当前目录下的目录链
		f=now->File_head;
	}
	if(d==0&&f==0)
	{
		cout<<"当前目录为空"<<endl;
		return 0;
	}
	cout<<"当前目录大小:";
	if(now==0)
		cout<<length;
	else
		cout<<now->length;
	cout<<endl;
	if(d==0)
		cout<<"当前目录下没有目录"<<endl;
	else
	{
		cout<<"当前目录下包含如下目录:"<<endl;
		cout<<setw(14)<<"目录名称"<<setw(14)<<"目录大小"<<endl;
		while(d!=0)
		{
			cout<<setw(14)<<d->name<<setw(14)<<d->length<<endl;
			d=d->next;
		}
	}
	if(f==0)
		cout<<"当前目录下没有文件"<<endl;
	else
	{
		cout<<"当前目录下包含如下文件:"<<endl;
		cout<<setw(14)<<"文件名称"<<setw(14)<<"文件大小"<<setw(14)<<"文件属性"<<endl;
		while(f!=0)
		{
			cout<<setw(14)<<f->name<<setw(14)<<f->length<<setw(14)<<f->attribute<<endl;
			f=f->next;
		}
	}
	return 1;
}

5.运行结果

5.1 运行环境
Windows x64
CPU2.8GHZ,8GB内存
Dev c++5.11编译器,idea(java)
5.2 服务模式
5.3 运行结果
5.3.1 系统主界面
Java模拟生产者与消费者的系统界面
在这里插入图片描述

5.3.2 多用户文件系统
系统首页
登录模块:可选择管理员模式和用户登录
在这里插入图片描述
管理员模式:
在这里插入图片描述
可在管理员模式创建系统用户,删除用户,查看当前用户。
用户模式:
在这里插入图片描述
用户模式可创建文件,删除文件,创建目录,删除目录,打开目录,返回上一层目录,查看当前目录,修改密码,查看文件。
创建文件:
在这里插入图片描述
创建目录:
在这里插入图片描述
打开目录:
在这里插入图片描述
查看当前目录:
在这里插入图片描述
直接查看文件:
在这里插入图片描述
删除目录:
在这里插入图片描述
删除文件:在这里插入图片描述

6.调试和改进

在文件系统设计中,为了减少检索文件访问的物理块的数量,文件系统把文件目录项中的文件名和其他管理信息分开,后者单独组成一定长度的数据结构,即为索引节点。把文件控制块的内容与索引节点分开,这样加快了目录检索速度,还便于实现文件共享,有利于系统的控制和管理。

7.心得和结论

7.1结论和体会

通过这次操作系统课程设计,进一步加深了我对文件属性,文件操作的认识,在文件系统的设计中,难点应该是文件目录的管理,其中文件控制块和索引节点结构起了重要作用。文件控制块中,包含了文件使用,文件管理等信息。在系统中查找文件时,根据文件名找到控制块,再通过控制块获取到文件信息。
在实现java模拟生产者与消费者问题上,使用synchronized对存储加锁,来实现同步机制,进一步理解wait()和notify的方法应用,只要java类拥有这两个办法,就可为任何对象实现同步机制。

7.2进一步改进方向

设计文件系统时,为了便于实现,对文件读写做了简化,在执行读写命令时,只修改读写的指针,并未真正进行读写操作,因此未来需要完善读写操作。还有要有文件保护措施,在每次打开文件时,应再次设置保护级别,便可有二级保护。

7.3 分析设计方案对系统安全的影响

在文件系统中,增加了用户和管理员的密码管理,通过密码的保护来实现多用户登录,多用户使用各自的控制块管理文件。
主要参考文献
[1]张尧学,宋虹,张高,《计算机操作系统教程》[M].清华大学出版社,2013.
[2] 汤小丹,梁红兵,哲凤屏,汤子瀛,《计算机操作系统》[M].西安电子科技大学出版社,2014.
[3]王育勤,等,《计算机操作系统》,北京交通大学出版社,2004
[4]倪光南. Linux影响软件界走向,成最热门话题
[5]倪光南. Linux影响软件界走向,成最热门话题

文件系统源代码cpp文件


#include<string.h>
#include<stdlib.h>
#include<iostream.h>
#include<iomanip.h>
#if _MSC_VER>1000
#pragma once
#endif	//_MSC_VER>1000
 
extern int disk_block[10000];
extern int disk_empty;


typedef struct PCB		//存储文件信息
{
	char name[10];		    //文件名
	int attribute;		     //属性
	int length;			      //长度
	int a[10];		        //为文件本身分配10个空间
	int *p1;			            //一级索引,100个空间
	int (*p2)[100];		            //二级索引,100*100个空间
	struct PCB *next;
}PCB;



typedef struct DIR		//存储目录信息
{
	char name[20];
	int length;
	DIR* above;			 //上一结点
	DIR *next;	         //下一结点
	PCB *File_head;		 //此目录下的文件指针
	DIR *Dir_head;		 //此目录下目录链表指针
}DIR;
 
class test				//定义管理用户目录的类
{
	DIR *now;			//当前目录
	PCB *Fhead;			//文件的头结点
	DIR *Dhead;			//根目录的目录链头结点
	char code[10];		//密码
	char name[10];		//用户名
	int length;			//用户空间大小
	int status;			//是否获得空间


public:
	void set_status(int);
	int dele_user();
	int dis_file();		//显示文件所占外存块号
	int dis_dir(DIR *d);//当前路径
	int get_length();
	char const *get_name();
	char const *get_code();
	int get_status();
	int set_user(char *,char *);//设置用户名与密码
	DIR *get_now();
	int dele_file(PCB *f);		//删除文件
	int dele_dir(DIR*);			//删除目录
	test();						//构造
	~test();					//析构
	int goback();				//返回上级
	int dis_now();				//显示当前目录
	int createfile();
	int new_dir();
	int open_dir();
	int open_file();
	int first_dele_file();		//删除文件的前部分工作
	int first_dele_dir();		//删除目录的前部分工作
	int set_code();
};
 
class Cdisk{					//用户类
public:
	test user[3];		  //用户个数 
	char code[10];
	int dis_disk();
	int first_dele_user();
	int dele_user(int);
	int createuser();				//查看当前用户与外存空间使用情况,后创建新用户
	int set_code();				//设置新密码
	int login(char);				//登录 
	Cdisk();
	virtual~Cdisk();			//虚函数,析构
};
 
int disk_block[10000];
int disk_empty;

Cdisk::Cdisk()		//管理磁盘的类,构造函数
{
	int i=0;
	char code[10]="123456";
	for(i=0;i<10000;i++)		//初始化所有磁盘块为空闲
		disk_block[i]=0;
	//this->user[0].set_user("student","123");//默认一个用户
	disk_empty=10000;
	cout.setf(ios::left);	//设置输出方式
}

Cdisk::~Cdisk()		//析构
{
}
 
int Cdisk::dele_user(int i)		//Cdisk类dele_user的构造
{
	test C;
	C=user[i];
	user[i].dele_user();		//调用Cuse类的成员函数 int dele_user()
	return 1;
}
 
int Cdisk::dis_disk()		//检查磁盘信息
{
	int i=0;
	cout<<setw(14)<<"用户名"<<setw(14)<<"占用空间大小"<<endl;
	for(i=0;i<3;i++)
		if(user[i].get_status()==1)		//存在的用户的信息
			cout<<setw(14)<<user[i].get_name()<<setw(14)<<user[i].get_length()<<endl;
		cout<<"已用空间:"<<10000-disk_empty<<endl<<"剩余空间:"<<disk_empty<<endl;
		return 1;
}

int Cdisk::login(char b)		//登录 
{
	char n[10],c[10];
	int i;
	if(b=='1')
	{
		cout<<"用户:管理员  密码:默认\n"<<endl;
		system("pause");
		return 1;
	}
	else
	{
		if(!user[0].get_status())	//当前不存在用户
		{
			i=0;
			cout<<"未注册用户,请注册用户!"<<endl;
			user[i].set_status(1);		//为新用户分配权利
			cout<<"请输入用户名:"<<endl;
			cin>>n;
			cout<<"请输入密码:"<<endl;
			cin>>c;
			user[i].set_user(n,c);		//调用Cuse的成员函数,传递用户名与密码
 
			cout<<"创建用户成功!"<<endl;
			return i;
		}
		else
		{
			cout<<"用户名:";
			cin>>n;
			cout<<"密码:";
			cin>>c;
			cout<<endl;
			for(i=0;i<3;i++)	//查找是否存在此用户
			{
				if(user[i].get_status())		//存在方比较
					if(!strcmp(n,user[i].get_name()))	//相等时为0,此判断为匹配
						if(!strcmp(c,user[i].get_code()))		//密码匹配
						{
							cout<<"登录成功!"<<endl;
							cout<<"欢迎"<<user[i].get_name()<<"登录"<<endl;
							return i;
						}
						else
						{
							cout<<"密码错误"<<endl;
							return -1;
						}
			}
			cout<<"此用户不存在!"<<endl;
			return -1;
		}
	}
}
 
int Cdisk::set_code()		//设置新密码
{
	char temp1[10],temp2[10];
	cout<<"请输入原密码"<<endl;
	cin>>temp1;
	if(strcmp(temp1,code))		//无疑是针对当前用户进行操作,故直接code
	{
		cout<<"原密码错误!"<<endl;
		return 0;
	}
	while(1)
	{
		cout<<"请输入新密码:"<<endl;
		cin>>temp1;
		cout<<"请再次输入新密码:"<<endl;
		cin>>temp2;
		if(strcmp(temp1,temp2))
		{
			cout<<"两次密码不相同,请重输!"<<endl;
			break;
		}
		cout<<"密码设置成功!"<<endl;
		strcpy(code,temp1);		//保存新密码
		break;
	}
	return 1;
}
 
int Cdisk::createuser()		//准备创建新用户
{
	char n[10],c[10];
	int i=0,j;
	for(i=0;i<3;i++)
		if(user[i].get_status()==0)		//是否有此用户,此尚未存在
			break;
		if(i==3)
		{
			cout<<"已经达到最大用户3个,不能再创建!"<<endl;
			return 0;
		}
		user[i].set_status(1);		//为新用户分配权利
		cout<<"请输入用户名:"<<endl;
		cin>>n;
		if(i>0)			//已有其它用户存在
		{
			for(j=0;j<i-1;j++)
				if(!strcmp(user[j].get_name(),n))
				{
					cout<<"此用户名已存在!"<<endl;
					return 0;
				}
		}
		cout<<"请输入密码:"<<endl;
		cin>>c;
		user[i].set_user(n,c);		//调用Cuse的成员函数,传递用户名与密码
		cout<<"用户创建成功!"<<endl;
		return 1;
}
 
int Cdisk::first_dele_user()		//删除用户
{
	char n[10],c;
	int i;
	cout<<"请输入你要删除的用户名"<<endl;
	cin>>n;
	for(i=0;i<3;i++)		//在查找用户的同时,得到用户序号i
		if(!strcmp(user[i].get_name(),n)&&user[i].get_status())
			break;		//找到,跳出
		if(i==3)
		{
			cout<<"出错,此用户不存在!"<<endl;
			return 0;
		}
		cout<<"确认删除此用户?确认Y,取消任意键"<<endl;
		cin>>c;
		if(c!='Y'&&c!='y')
		{
			cout<<"已经取消删除!"<<endl;
			return 0;
		}
		this->dele_user(i);
		cout<<"用户删除成功"<<endl;
		return 1;
}
 
test::test()		//构造函数,初始化成员
{
	status=0;		//用户权利,即是否被创建标记
	length=0;		//空间
	now=0;			//当前目录
	Fhead=0;		//文件
	Dhead=0;		//目录
}
 
test::~test()		//析构,清除程序占用的内存
{
	disk_empty+=length;
	length=0;
	PCB *f=Fhead;
	DIR *d=Dhead;
	while(f!=0)		//文件
	{
		if(f->next==0)
		{
			this->dele_file(f);
			f=0;
			break;
		}
		while(f->next->next!=0)
			f=f->next;
		this->dele_file(f->next);
		f->next=0;
		f=Fhead;
	}
	while(d!=0)		//目录
	{
		if(d->next==0)
		{
			this->dele_dir(d);
			d=0;
			break;
		}
		while(d->next->next!=0)
			d=d->next;
		this->dele_dir(d->next);
		d->next=0;
		d=Dhead;
	}
}
 
 
int test::createfile()		//建立新文件
{
	int i=0,j=0;
	PCB *f,*p=0;
	DIR *D;
 
	p=new PCB;				//开辟一个新的文件结构体
	if(p==0)
	{
		cout<<"无可用内存空间,创建文件失败!"<<endl;
		return 1;
	}
	cout<<"请输入建立的文件名:";
	cin>>p->name;
	if(now==0)			//根目录下的文件链
		f=Fhead;
	else				//当前目录下的文件链
		f=now->File_head;
	while(f!=0)			//检查是否文件重名
	{
		if(!strcmp(p->name,f->name))
		{
			cout<<"此文件已存在!"<<endl;
			return 0;	//退出
		}
		f=f->next;
	}
	cout<<"\n"<<"长度:";
	cin>>p->length;
	cout<<"\n"<<"属性(0:只读,1:读写):";
	cin>>p->attribute;
	cout<<endl;
	if(p->length>disk_empty)		//空间不足
	{
		cout<<"文件太大,空间不足,当前空间为:"<<disk_empty<<endl;
		delete p;
		return 0;
	}
	disk_empty=disk_empty-p->length;	//剩余空闲盘块
	//
	for(i=0;i<p->length&&i<10;i++)		//文件较小时,直接地址,文件数据盘块号
		for(j;j<10000;j++)				
			if(disk_block[j]==0)		//空闲
			{
				p->a[i]=j;				//得到此空间
				disk_block[j]=1;		//标记为已分配出去
				j++;
				break;					//跳出寻找,为文件分配下一空间
			}
			p->p1=0;					//一级索引
			p->p2=0;					//二级索引
			if(p->length>10)			//超过10,用一级索引
			{
				p->p1=new int[100];		//为一级索引分配100个空间
				for(i=10;i<p->length&&i<110;i++)
					for(j;j<10000;j++)		//j,继续前面的值
						if(disk_block[j]==0)
						{
							(p->p1)[i-10]=j;
							disk_block[j]=1;
							j++;
							break;
						}
						if(p->length>110)			//超过110,得用二级索引
						{
							p->p2=new int[100][100];	//在一级索引的基础上,2维
							for(i=110;i<p->length;i++)
								for(j;j<10000;j++)		//j,继续前面的值
									if(disk_block[j]==0)
									{
										int m=(i-110)/100;		//行
										int k=(i-110)%100;		//列
										p->p2[m][k]=j;
										disk_block[j]=1;
										j++;
										break;
									}
						}
			}
			if(now==0)	//根目录下的文件
			{
				p->next=Fhead;	//后继结点指向头,即新指点在前
				Fhead=p;	//新结点在头
			}
			else
			{
				p->next=now->File_head;
				now->File_head=p;
			}
			length+=p->length;	//用户总空间大小增加
			if(now!=0)			//子目录下空间大小增加
			{
				now->length+=p->length;
				D=now->above;	//上一级目录
				while(D!=0)		//上级目录(根目录已实现)空间增加
				{
					D->length+=p->length;
					D=D->above;		//逐级向上
				}
			}
 
			return 0;
}
 
int test::new_dir()		//建立新目录
{
	DIR *p,*h;
	cout<<"请输入新目录的名字:"<<endl;
	p=new DIR;
	cin>>p->name;		//目录名
	p->Dir_head=0;		//目录下的目录链为空
	p->length=0;		//
	p->File_head=0;		//目录下的文件为空
	if(now==0)			//当前为主目录
		h=Dhead;	//第一次时,h=0;指向目录链
	else
		h=now->Dir_head;//当前的目录链
	while(h!=0)	//此目录下存在其它子目录
	{
		if(!strcmp(h->name,p->name))
		{
			cout<<"此目录已存在!"<<endl;
			return 0;
		}
		h=h->next;
	}
	if(now==0)		//当前为主目录
	{
		p->above=0;		//主目录里目录的上一结点为0
		p->next=Dhead;		//把原目录接入新目录后面(Dhead初始为0)
		Dhead=p;		//Dhead始终指向最新目录结点
	}
	else
	{
		p->above=now;		//当前目录为新目录的上一结点
		p->next=now->Dir_head;	//反序插入新目录
		now->Dir_head=p;	//更新目录链
	}
	cout<<"目录创建成功"<<endl;
	return 1;
}
 
int test::goback()		//向上返回
{
	if(now==0)
	{
		cout<<"已是主目录,不能向上!"<<endl;
		return 0;
	}
	now=now->above;		//上一结点
	return 1;
}
 
int test::open_dir()	//打开目录
{
	char name[10];
	DIR *p;
	if(now==0)	//当前主目录
		p=Dhead;
	else
		p=now->Dir_head;	//p指向目录链
	cout<<"请输入你要打开的目录名:"<<endl;
	cin>>name;
	//int flag=0;
	while(p!=0)
	{
		if(strcmp(p->name,name)==0)
		{
			now=p;	      //找到目录,now标记
			return 1;
		}
		p=p->next;
	}
	cout<<"当前没此目录"<<endl;
	return 0;
}
 
int test::first_dele_file()	                     //删除文件的前面工作
{
	char temp[10],a[5];
	cout<<"你要删除的文件名:"<<endl;
	cin>>temp;
	PCB *f=Fhead;	//数据文件头指针
	PCB *above=0;
	if(now!=0)
		f=now->File_head;	//当前目录下的数据文件
	while(f!=0)
	{
		if(!strcmp(f->name,temp))
			break;	//找到,跳出
		above=f;	//标记第一个文件
		f=f->next;
	}
	if(f==0)
	{
		cout<<"此文件不存在"<<endl;
		return 0;
	}
	cout<<"确定删除"<<f->name<<"文件吗?按0确定,其他键取消"<<endl;
	cin>>a;
	if(a[0]!='0')
	{
		cout<<"已取消删除文件。"<<endl;
		return 0;
	}
	disk_empty+=f->length;	//回收此数据文件的空间大小
	if(now==0)	//根目录
	{
		if(f==Fhead)
			Fhead=Fhead->next;
		else
			above->next=f->next;
	}
	else
	{
		DIR *d=now;
		while(d!=0)
		{
			d->length=f->length;
			d=d->above;
		}
		if(f==now->File_head)
			now->File_head=now->File_head->next;
		else
			above->next=f->next;
	}
	length-=f->length;
	this->dele_file(f);
	cout<<"删除成功"<<endl;
	return 1;
}
 
int test::dele_file(PCB *f)	                   //具体实现删除文件
{
	int i=0,m;
	for(i=0;i<10&&i<f->length;i++)	//回收文件具体空间,重置空闲
	{
		m=f->a[i];
		disk_block[m]=0;
	}
	if(f->p1!=0)	//回收一级索引
	{
		for(i=10;i<110&&i<f->length;i++)
		{
			m=f->p1[i-10];
			disk_block[m]=0;
		}
		delete[](f->p1);
	}
	if(f->p2!=0)	//回收二级索引
	{
		for(i=110;i<f->length;i++)
		{
			m=(f->p2)[(i-110)/100][(i-110)%100];
			disk_block[m]=0;
		}
		delete[](f->p2);
		delete f;
	}
	f=0;	//要删除的文件为空了
	return 1;
}
 
int test::first_dele_dir()	//删除目录的前奏
{
	char n[10];
	char c;
	DIR *p,*above=0;
	p=Dhead;	//指向根目录下的目录链
	if(now!=0)
		p=now->Dir_head;	//指向当前目录下的目录链
	cout<<"要删除的目录名:"<<endl;
	cin>>n;
	while(p!=0)
	{
		if(!strcmp(p->name,n))
			break;	//找到要删除的目录,跳出
		above=p;	//保存前一结点
		p=p->next;
	}
	if(p==0)
	{
		cout<<"没有这个目录!"<<endl;
		return 0;
	}
	cout<<"确定删除当前目录及此目标上的所有信息吗?按0确定,其他键取消"<<endl;
	cin>>c;
	if(c!='0')
		return 0;
	disk_empty+=p->length;	//回收磁盘空间
	if(now==0)
	{
		if(p==Dhead)	//如果是根目录下头结点,直接移动Dhead
			Dhead=Dhead->next;
		else
			above->next=p->next;//中间抽掉目标
	}
	else
	{
		if(p==now->Dir_head)
			now->Dir_head=now->Dir_head->next;
		else
			above->next=p->next;
		above=now;	//当前目录
		while(above!=0)
		{
			above->length-=p->length;//用above标记当前目录,进行大小更新
			above=above->above;	//向上一级
		}
	}
	length-=p->length;	//根目录大小更新
	this->dele_dir(p);
	p=0;
	cout<<"删除成功!"<<endl;
	return 1;
}
 
int test::dele_dir(DIR *p)	//具体实现删除目录的工作
{
	int flag=0;
	DIR *d=p->Dir_head;	//当前目录下的目录链表
	PCB *f=p->File_head;	//当前目录下的文件链
	if(f!=0)
	{
		while(p->File_head->next!=0)//删除目录里的文件
		{
			f=p->File_head;
			while(f->next->next!=0)
				f=f->next;
			this->dele_file(f->next);
			f->next=0;
		}
		if(p->File_head->next==0)
		{
			this->dele_file(p->File_head);   //删除头文件
			p->File_head=0;
		}
	}
	if(d!=0)	//删除目录下的目录
	{
		while(p->Dir_head->next!=0)
		{
			d=p->Dir_head;
			while(d->next->next!=0)
				d=d->next;
			this->dele_dir(d->next);
			d->next=0;
		}
		if(p->Dir_head->next==0)
		{
			this->dele_dir(p->Dir_head);//删除目录链头结点
			p->Dir_head=0;
		}
	}
	delete p;	//释放p占用的内存
	p=0;		//置0
	return 1;
}
 
int test::dis_now()	//显示当前目录
{
	DIR *d=Dhead;
	PCB *f=Fhead;
	if(now!=0)
	{
		d=now->Dir_head;	//当前目录下的目录链
		f=now->File_head;
	}
	if(d==0&&f==0)
	{
		cout<<"当前目录为空"<<endl;
		return 0;
	}
	cout<<"当前目录大小:";
	if(now==0)
		cout<<length;
	else
		cout<<now->length;
	cout<<endl;
	if(d==0)
		cout<<"当前目录下没有目录"<<endl;
	else
	{
		cout<<"当前目录下包含如下目录:"<<endl;
		cout<<setw(14)<<"目录名称"<<setw(14)<<"目录大小"<<endl;
		while(d!=0)
		{
			cout<<setw(14)<<d->name<<setw(14)<<d->length<<endl;
			d=d->next;
		}
	}
	if(f==0)
		cout<<"当前目录下没有文件"<<endl;
	else
	{
		cout<<"当前目录下包含如下文件:"<<endl;
		cout<<setw(14)<<"文件名称"<<setw(14)<<"文件大小"<<setw(14)<<"文件属性"<<endl;
		while(f!=0)
		{
			cout<<setw(14)<<f->name<<setw(14)<<f->length<<setw(14)<<f->attribute<<endl;
			f=f->next;
		}
	}
	return 1;
}
 
int test::open_file()	//打开文件
{
	char n[10];
	cout<<"请输入要打开的文件名"<<endl;
	cin>>n;
	PCB *f=Fhead;	//文件头指针
	if(now!=0)
		f=now->File_head;	//指向文件
	while(f!=0)
	{
		if(!strcmp(f->name,n))
		{
			cout<<"文件打开成功"<<endl;
			return 1;
		}
		f=f->next;
	}
	cout<<"当前目录无此文件"<<endl;
	return 0;
}
 

DIR *test::get_now()	//得到当前目录路径
{
	return now;
}
 
int test::set_user(char *n,char *c)//建立用户与密码
{
	strcpy(name,n);
	strcpy(code,c);
	status=1;
	return 1;
}
 
void test::set_status(int b)//标记分配
{
	status=b;
}
 
int test::get_status()//探取是否分配
{
	return status;
}
 
const char* test::get_code()//得到密码
{
	return code;
}
 
const char* test::get_name()//得到名字
{
	return name;
}
 
int test::get_length()//得到长度
{
	return length;
}
 
int test::dis_dir(DIR *d)//显示目录
{
	if(d==0)
		return 0;
	if(d->above!=0)
		this->dis_dir(d->above);//递归调用此功能
	cout<<"	"<<d->name<<'\n';
	return 0;
}
 
int test::dis_file()//查看文件
{
	int i;
	char n[10];
	PCB *f=Fhead;
	if(now!=0)
		f=now->File_head;
	cout<<"请输入要查看的文件名:"<<endl;
	cin>>n;
	while(f!=0)
	{
		if(!strcmp(n,f->name))	//找到此文件,跳出
			break;
		f=f->next;
	}
	if(f==0)
	{
		cout<<"当前目录下没此文件"<<endl;
		return 0;
	}
	if(f->attribute==0)
		cout<<"此为只读文件,";
	else
		cout<<"此为读写文件,";
	cout<<"占用硬盘块号如下:"<<endl;
	for(i=0;i<f->length&&i<10;i++)		//直接存放的
	{
		cout<<setw(6)<<f->a[i];
		if((i+1)%10==0)
			cout<<endl;
	}
	for(i=10;i<f->length&&i<110;i++)	//一级索引存放的
	{
		cout<<setw(6)<<f->p1[i-10];
		if((i+1)%10==0)
			cout<<endl;
	}
	for(i=110;i<f->length;i++)	//二级索引存放的
	{
		cout<<setw(6)<<f->p2[(i-110)/100][(i-110)%100];
		if((i+1)%10==0)
			cout<<endl;
	}
	cout<<endl;
	return 1;
}
 
int test::dele_user()//删除用户
{
	length=0;	//用户空间置0
	Fhead=0;
	Dhead=0;
	now=0;
	status=0;
	return 1;
}
 
 
int main()
{
	char c;
	Cdisk D;		           //管理员类的对象
	int i=1,n,flag=1,t=0;
 
	while(flag)
	{
		cout<<"---------------多用户文件系统----------------"<<endl;
		cout<<"        1.管理员"<<endl;
		cout<<"        2.用户登录"<<endl;
		cout<<"        3.退出"<<endl;
		cout<<endl;
		cout<<""<<endl;
 
		cout<<"请选择操作:";
		cin>>c;
		switch(c)
		{
		case '1':
			n=D.login(c);
			flag=1;
			system("cls");
			cout<<"管理员登录成功!"<<endl;
			while(flag)
			{
				cout<<""<<endl;
				cout<<"1.创建用户"<<endl;
				cout<<"2.删除用户"<<endl;
				cout<<"3.查看当前用户"<<endl;
				cout<<"4.返回登录窗口"<<endl;
				cout<<"---------------------------"<<endl;
				cout<<"请选择操作:";
				cin>>c;
				cout<<endl;
				switch(c){
				case '1':
					D.createuser();
					break;
				case '2':
					D.first_dele_user();
					break;
				case '3':
					D.dis_disk();
					break;
				case '4':
					/*{
						if(t==0)	//t作标记,防止重复设置密码出错
							strcpy(D.code,"123");
						D.set_code();
						t++;
						break;
					}*/ 
					{
						flag=0;
						system("cls");
					}
				/*case '5':
					{
						flag=0;
						system("cls");
					}*/ 
					break;
				default:
					cout<<"请输入1-4!"<<endl;
				}
			}
			flag=1;
			break;
		case '2':
			n=D.login(c);
			if(n==-1)
				break;
			while(flag)
			{
				cout<<"----------------------------------------------"<<endl;
				cout<<"1.创建文件         2.删除文件"<<endl;
				
				cout<<"3.创建目录         4.删除目录"<<endl;
				
				cout<<"5.打开目录         6.返回上一级目录"<<endl;
				
				cout<<"7.查看当前目录     8.查看文件"<<endl;
				
				cout<<"0.退出"<<endl;
				
				cout<<"-----------------------------------------------"<<endl;
				cout<<"用户:"<<D.user[n].get_name()<<'\n'<<"目录为:\nroot\n";
				D.user[n].dis_dir(D.user[n].get_now());
				cout<<endl;
				cout<<"请输入选择:";
				cin>>c;
				cout<<endl;
				switch(c)
				{
				case '1':
					D.user[n].createfile();
					break;
				case '2':
					D.user[n].first_dele_file();
					break;
				case '3':
					D.user[n].new_dir();
					break;
				case '4':
					D.user[n].first_dele_dir();
					break;
				case '5':
					D.user[n].open_dir();
					break;
				case '6':
					D.user[n].goback();
					break;
				case '7':
					D.user[n].dis_now();
					break;
				case '8':
					D.user[n].dis_file();//D.user[n].set_code();
					break;
				case '0':
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
					{
						flag=0;
						system("cls");
					}
					break;
				default:
					cout<<"请输入0-9"<<endl;
				}
			}
			flag=1;
			break;
		case '3':
			flag=0;
			break;
		default:
			cout<<"请输入1-3!"<<endl;
			}
		}
}
相关推荐
设计一: 设计任务:模拟Linux文件系统 在任一OS下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的模拟Linux文件系统。 1. 在现有机器硬盘上开辟100M的硬盘空间,作为设定的硬盘空间。 2. 编写一管理程序simdisk对此空间进行管理,以模拟Linux文件系统,要求: (1) 盘块大小1k (2) 空闲盘块的管理:Linux位图法 (3) 结构:超级块, i结点区, 根目录区 3. 该simdisk管理程序的功能要求如下: (1) info: 显示整个系统信息(参考Linux文件系统的系统信息),文件可以根据用户进行读写保护。目录名和文件名支持全路径名和相对路径名,路径名各分量间用“/”隔开。 (2) cd …: 改变目录:改变当前工作目录,目录不存在时给出出错信息。 (3) dir …: 显示目录:显示指定目录下或当前目录下的信息,包括文件名、物理地址、保护码、文件长度、子目录等(带/s参数的dir命令,显示所有子目录)。 (4) md …: 创建目录:在指定路径或当前路径下创建指定目录。重名时给出错信息。 (5) rd …: 删除目录:删除指定目录下所有文件和子目录。要删目录不空时,要给出提示是否要删除。 (6) newfile …: 建立文件。 (7) cat …: 打开文件。 (8) copy …: 拷贝文件,除支持模拟Linux文件系统内部的文件拷贝外,还支持host文件系统与模拟Linux文件系统间的文件拷贝,host文件系统的文件命名为<host>…,如:将windows下D:盘的文件\data\sample\test.txt文件拷贝到模拟Linux文件系统中的/test/data目录,windows下D:盘的当前目录为D:\data,则使用命令: simdisk copy <host>D:\data\sample\test.txt /test/data 或者:simdisk copy <host>D:sample\test.txt /test/data (9) del …: 删除文件:删除指定文件,不存在时给出出错信息。 (10) check: 检测并恢复文件系统:对文件系统中的数据一致性进行检测,并自动根据文件系统的结构和信息进行数据再整理。 4. 程序的总体流程为: (1) 初始化文件目录; (2) 输出提示符,等待接受命令,分析键入的命令; (3) 对合法的命令,执行相应的处理程序,否则输出错误信息,继续等待新命令,直到键入EXIT退出为止。 设计二: 设计任务:模拟文件系统的前端操作shell 实现一个简单的shell(命令行解释器)。 将设计一的管理程序simdisk作为后台进程运行,利用本设计任务的shell操作simdisk。 本设计任务在于学会如何实现在前端的shell进程和后端的simdisk进程之间利用共享内存进行进程间通信(IPC)。 设计三: 设计任务:模拟文件系统的操作管理 实现多个进程同时对模拟文件系统进行操作。设计管理程序simdisk的用户访问权限管理。访问模拟文件系统的每个进程都属于某个用户,管理程序simdisk根据其访问权限决定其对模拟文件系统的操作。 对模拟文件系统的操作要求做到:共享读,互斥写。 本设计任务在于学会如何实现信息的安全管理和进程同步。 注:要求从课程设计的整体来考虑设计任务一、二、三,并分阶段实现。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页