广工操作系统实验报告 下载本文

操作系统实验报告

学生学院 计算机学院 专业班级2010级计算机科学与技术四班 学 号 3110006015 学生姓名 张法光 指导教师 何翠红

2013年 1月 05 日

目录

实验一、进程调度...............................................................................4 实验二、作业调度...............................................................................8 实验三、动态分区分配方式的模拟 ..................................................16 实验四、文件系统.............................................................................24

3

1 实验一 进程调度

1、 实验目的

编写并调试一个模拟的进程调度程序,采用“短进程优先”调度算法对五个进程进行调度。以加深对进程的概念及进程调度算法的理解.

2、实验原理

在多道程序系统中,一个作业被提交后必须经过处理机调度后,方能获

得处理机执行。对调度的处理又都可采用不同的调度方式和调度算法。调度算法是指:根据系统的资源分配策略所规定的资源分配算法。

短进程优先调度算法是指对短进程优先调度的算法,它是从后备队列中选

择一个或者若干个进程,将处理机分配给它,使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时再重新调度。

短进程优先调度源程序如下:

#include #define n 5 #define num 5 #define max 65535 typedef struct pro {

int PRO_ID;//进程号 int arrive_time;//到达时间 int sum_time;//运行总时间 int flag;

}Pro;

//整数排序

int bubble(int temp[]) {

int i,j,tem=0;

for(i=1;i

4

{ }

int lastX=1;

for(j=0;jtemp[j+1]) }

{

tem=temp[j]; temp[j]=temp[j+1]; temp[j+1]=tem; lastX=0; }

if(lastX==1) break;

}

return temp[0];

//进程排序

Pro bubble(Pro p[]) {

int i,j;

Pro temp={0}; Pro s[num];

for(i=0;i

for(i=1;i

return s[0];

int lastX=1;

for(j=0;j

if(s[j].sum_time>s[j+1].sum_time) {

temp=s[j]; s[j]=s[j+1]; s[j+1]=temp; lastX=0; }

if(lastX==1) break;

}

5

void SPF(int p) {

if(n>0) {

int i,j,k,l,tc=0;

Pro seq[n]; Pro temp_seq[n];

printf(\ printf(\计科4班 张法光 3110006015\\n\

printf(\

printf(\实验一:短进程优先调度算法SPF\\n\

printf(\请依次输入5个进程的进程号、到达时间和执行时间\\n\printf(\成员变量用逗号隔开;进程间用回车隔开\\n\

printf(\ for(i=0;i

temp[i]=seq[i].arrive_time;

}

tc=bubble(temp);//tc是断点啊

//flag 表示对应i的pro的队列情况

//-1表示未进入过队列,0表示在队列中,1表示被清除了 for(i=0;i

}

for(i=0;i

for(j=0;j

if(seq[j].flag!=1&&seq[j].arrive_time<=tc){ }

seq[j].flag=0; }

for(j=0;j

if(seq[j].flag!=0){ temp_seq[j].sum_time=max; }

6

}

}

}

l=bubble(temp_seq).PRO_ID; for(j=0;j

}

}

tc=tc+bubble(temp_seq).sum_time; seq[k].flag=1; printf(\}

printf(\

void main() { }

SPF(n);

运行结果:

结果分析与实验小结

非抢占式的短进程优先调度相对简单,有个易错的地方就是最早来的不管所需服务时间长短均必须先服务,而且数量可能不止一个,此时可以再根据短进程优先法则调度。总的来说,短进程优先调度算法可以照顾到实际上在所有进程中占很大比例的短进程,使它能比长进程优先执行,但不利于长进程的执行。

7

2 实验二 作业调度

1、实验目的

本实验要求学生模拟作业调度的实现,用高级语言编写和调试一个或多个作业调度的模拟程序,了解作业调度在操作系统中的作用,以加深对作业调度算法的理解。

2、实验内容及要求

1、为单道批处理系统设计一个作业调度程序

(1)、编写并调试一个单道处理系统的作业调度模拟程序。 (2)、作业调度算法:分别采用先来先服务(FCFS)、响应比高者优先(HRN)

的调度算法。

(3)、由于在单道批处理系统中,作业一投入运行,它就占有计算机的一切

资源直到作业完成为止,因此调度作业时不必考虑它所需要的资源是否得到满足,它所占用的 CPU时限等因素。 (4)、每个作业由一个作业控制块JCB表示,JCB可以包含如下信息:作业名、

提交时间、所需的运行时间、所需的资源、作业状态、链指针等等。作业的状态可以是等待W(Wait)、运行R(Run)和完成F(Finish)三种状态之一。每个作业的最初状态总是等待W。

(5)、对每种调度算法都要求打印每个作业开始运行时刻、完成时刻、周转

时间、带权周转时间,以及这组作业的平均周转时间及带权平均周转时间,并比较各种算法的优缺点。

2、模拟批处理多道操作系统的作业调度 (1)、写并调试一个作业调度模拟程序。

(2)、作业调度算法:分别采用先来先服务(FCFS)和短作业优先调度算法。 (3)、在批处理系统中,要假定系统中具有的各种资源及数量、调度作业时

必须考虑到每个作业的资源要求,所需要的资源是否得到满足。 作业调度程序负责从输入井选择若干个作业进入主存,为它们分配必要的资源,当它们能够被进程调度选中时,就可占用处理器运行。作业调度选择一个作业的必要条件是系统中现有的尚未分配的资源可满足该作业的资源要求。但有时系统中现有的尚未分配的资源既可满足某个作业的要求也可满足其它一些作业的要求,那么,作业调度必须按一定的算法在这些作业中作出选择。当作业正常运行完毕或因发生错误非正常终止时,作业进入完成状态,此时,系统将收回该作业所占用的全部资源,并清除有关的JCB。并输出显示作业运行情况及作业输出结果。

3、实验设计方案及原理

1、编写并调试一个单道处理系统的作业等待模拟程序。

假设在单道批处理环境下有四个作业JOB1、JOB2、JOB3、JOB4,已知它们进入系统的时间、估计运行时间。分别采用先来先服务(FCFS),最短作业优先(SJF)、响应比高者优先(HRN)的调度算法,计算出作业的平均周转时间和带权的平均周转时间 。

8

对每种调度算法都要求打印每个作业开始运行时刻、完成时刻、周转时间、带权周转时间,以及这组作业的平均周转时间及带权平均周转时间,并比较各种算法的优缺点。

4、源程序清单(需附详细的注释)

#include #include #include

#define getpch(type) (type*)malloc(sizeof(type)) #define null 0 int n;

float T1=0,T2=0; int times=0;

struct jcb //作业控制块 {

char name[10]; //作业名

int reachtime; //作业到达时间 int starttime; //作业开始时间

int needtime; //作业需要运行的时间 float super; //作业的响应比 int finishtime; //作业完成时间 float cycletime; //作业周转时间

float cltime; //作业带权周转时间 char state; //作业状态 struct jcb *next; //结构体指针 }*ready=NULL,*p,*q;

typedef struct jcb JCB;

void inital() //建立作业控制块队列,先将其排成先来先服务的模式队列 {

int i;

printf(\输入作业数:\scanf(\for(i=0;i

{

p=getpch(JCB);

printf(\输入作业名:\ scanf(\ getch();

p->reachtime=i;

printf(\作业默认到达时间:%d\ printf(\输入作业要运行的时间:\ scanf(\ p->state='W';

9

p->next=NULL;

if(ready==NULL) ready=q=p; else{

q->next=p; q=p; } }

}

void output(JCB* q,int j) { /*显示所有作业的情况*/ JCB *pr=ready;float f=0.0;

printf(\所有作业的情况: \\n\列表显示所有作业的情况

if(j==3) {

printf(\作业名\\t\\t到达时间\\t所需运行间\\t响应比\\t\\t作业状态\\n\ printf(\ while(pr) {

if(pr->super<=0)

printf(\

pr->name,pr->reachtime,pr->needtime,f,pr->state); else printf(\pr->name,pr->reachtime,pr->needtime,pr->super,pr->state);

pr = pr->next; }

}

else {

printf(\作业名\\t\\t到达时间\\t所需运行间\\t作业状态\\n\

printf(\ while(pr) { printf(\pr->name,pr->reachtime,pr->needtime,pr->state); pr = pr->next; } }

}

void disp(JCB* q,int m) //显示作业运行后的周转时间及带权周转时间等 {

if(m==3) //显示高响应比算法调度作业后的运行情况 { output(q,m);

printf(\作业%s正在运行,估计其运行情况:\\n\

printf(\开始运行时刻\\t完成时刻\\t周转时间\\t带权周转时间\\t相应比\\n\\n\ printf(\ getch();

}

else // 显示先来先服务,最短作业优先算法调度后作业的运行情况 {

output(q,m);

printf(\作业%s正在运行,估计其运行情况:\\n\

10

printf(\开始运行时刻\\t完成时刻\\t周转时间\\t带权周转时间\\n\\n\

printf(\ getch(); } }

void running(JCB *p,int m) //运行作业

{

if(p==ready) //先将要运行的作业从队列中分离出来 {

ready=p->next; p->next=NULL; } else {

q=ready;

while(q->next!=p) q=q->next;

q->next=p->next; }

p->starttime=times; //计算作业运行后的完成时间,周转时间等等 p->state='R';

p->finishtime=p->starttime+p->needtime;

p->cycletime=(float)(p->finishtime-p->reachtime);

p->cltime=(float)(p->cycletime/p->needtime); T1+=p->cycletime; T2+=p->cltime;

disp(p,m); //调用disp()函数,显示作业运行情况

times+=p->needtime; p->state='F';

printf(\作业%s已经完成!\\n请输入任意键继续......\\n\free(p); //释放运行后的作业

getch();

}

void super() //计算队列中作业的高响应比 {

JCB *padv;

padv=ready;

do{ if(padv->state=='W'&&(padv->reachtime)<=times) {

padv->super=(float)(times-padv->reachtime+padv->needtime)/padv->needtime;

}

padv=padv->next; }while(padv!=NULL);

}

void final() //最后打印作业的平均周转时间,平均带权周转时间 {

float s,t;

11

t=T1/n;

s=T2/n; getch();

printf(\作业已经全部完成!\

printf(\个作业的平均周转时间是:%f\

printf(\个作业的平均带权周转时间是%f:\\n\\n\\n\}

void hrn(int m) //高响应比算法 {

JCB *min; int i,iden; system(\ inital();

for(i=0;i

{

p=min=ready;iden=1;

super(); do{ if(p->state=='W'&&p->reachtime<=times) if(iden) {

min=p;iden=0; }

else if(p->super>min->super) min=p; p=p->next; }while(p!=NULL);

running(min,m); //调用running()函数 } //for

final(); //调用running()函数 }

void fcfs(int m) //先来先服务算法 {

int i,iden; system(\ inital();

for(i=0;i

p=ready;iden=1; do{

if(p->state=='W'&&p->reachtime<=times) iden=0; if(iden)p=p->next; }while(p!=NULL&&iden) ; if(iden)

{

i--;printf(\没有满足要求的进程,需等待\ times++;

12

if(times>100){printf(\时间过长\ } else{

running(p,m); //调用running()函数 }

}

final(); //调用running()函数 }

void main() //主函数 {

int m;

while(1){

printf(\ printf(\计科4班 张法光 3110006015\\n\ printf(\实验2-作业调度系统\\n\ printf(\先来先服务算法\\n\

printf(\响应比高者优先算法\\n\ printf(\退出程序\\n\

printf(\ printf(\选择所要操作:\\n\

scanf(\ switch(m) {

case 1: fcfs(m);

getch();

times=0; main(); break; case 2: hrn(m); getch(); times=0; main(); break; case 3: exit(0);

default:

printf(\选择错误,重新选择.\ getch();

system(\ }

13

} }

5、程序运行结果

5.1先来先服务算法

14

5.2响应比高者优先算法

6、结果分析与实验小结

参考了几个作业调度的范例,作业调度实践起来并不难,但需要慢慢调试。和同学讨论了设计思路之后就开始做了,虽然有小错误,但是经过反复调试也修正了BUG。

15

3 实验三 动态分区分配方式的模拟

1、实验目的:了解动态分区分配方式中的数据结构和分配算法,并进一步加深对动态分区存储管理方式及其实现过程的理解 2、实验内容:

(1)用C语言分别实现采用首次适应算法和最佳适应算法的动态分区分配过程和回收过程。其中,空闲分区通过空闲分区链(表)来管理;在进行内存分配时,系统优先使用空闲区低端的空间。

(2)假设初始状态下,可用的内存空间为640KB,并有下列的请求序列: ?作业1申请130KB ?作业2申请60KB ?作业3申请100KB ?作业2释放60KB ?作业4申请200KB ?作业3释放100KB ?作业1释放130KB ?作业5申请140KB ?作业6申请60KB ?作业7申请50KB ?作业8申请60KB

请分别采用首次适应算法和最佳适应算法进行内存的分配和回收,要求每次分配和回收后显示出空闲内存分区链的情况。 3、思考:讨论各种分配算法的特点。

(1)首次适应算法。使用该算法进行内存分配时,从空闲分区链首开始查找,直至找到一个能满足其大小要求的空闲分区为止。然后再按照作业的大小,从该分区中划出一块内存分配给请求者,余下的空闲分区仍留在空闲分区链中。

该算法倾向于使用内存中低地址部分的空闲分区,在高地址部分的空闲分区很少被利用,从而保留了高地址部分的大空闲区。显然为以后到达的大作业分配大的内存空间创造了条件。缺点在于低址部分不断被划分,留下许多难以利用、很小的空闲区,而每次查找又都从低址部分开始,这无疑会增加查找的开销。

(2)最佳适应算法。该算法总是把既能满足要求,又是最小的空闲分区分配给作业。 为了加速查找,该算法要求将所有的空闲区按其大小排序后,以递增顺序形成一个空白链。这样每次找到的第一个满足要求的空闲区,必然是最优的。孤立地看,该算法似乎是最

16

优的,但事实上并不一定。因为每次分配后剩余的空间一定是最小的,在存储器中将留下许多难以利用的小空闲区。同时每次分配后必须重新排序,这也带来了一定的开销。

4、源程序清单(需附详细的注释)

#include #include

#define Free 0 //空闲状态 #define Busy 1 //已用状态 #define OK 1 //完成 #define ERROR 0 //出错

#define MAX_length 640 //最大内存空间为640KB typedef int Status;

typedef struct freearea//定义一个空闲区说明表结构 { int ID; //分区号 long size; //分区大小 long address; //分区地址 int state; //状态 }ElemType;

//---------- 线性表的双向链表存储结构 ------------ typedef struct DuLNode //double linked list { ElemType data; struct DuLNode *prior; //前趋指针 struct DuLNode *next; //后继指针 }DuLNode,*DuLinkList;

DuLinkList block_first; //头结点 DuLinkList block_last; //尾结点

Status alloc(int);//内存分配 Status free(int); //内存回收

Status First_fit(int,int);//首次适应算法 Status Best_fit(int,int); //最佳适应算法 void show();//查看分配

Status Initblock();//开创空间表

Status Initblock()//开创带头结点的内存空间链表 {

17

block_first=(DuLinkList)malloc(sizeof(DuLNode)); block_last=(DuLinkList)malloc(sizeof(DuLNode)); block_first->prior=NULL; block_first->next=block_last; block_last->prior=block_first; block_last->next=NULL; block_last->data.address=0; block_last->data.size=MAX_length; block_last->data.ID=0; block_last->data.state=Free; return OK; }

//----------------------- 分 配 主 存 ------------------------- Status alloc(int ch) { int ID,request; cout<<\请输入作业(分区号):\ cin>>ID; cout<<\请输入需要分配的主存大小(单位:KB):\ cin>>request; if(request<0 ||request==0) { cout<<\分配大小不合适,请重试!\ return ERROR; } if(ch==2) //选择最佳适应算法 { if(Best_fit(ID,request)==OK) cout<<\分配成功!\ else cout<<\内存不足,分配失败!\ return OK; } else //默认首次适应算法 { if(First_fit(ID,request)==OK) cout<<\分配成功!\ else cout<<\内存不足,分配失败!\ return OK; } }

//------------------ 首次适应算法 ----------------------- Status First_fit(int ID,int request)//传入作业名及申请量 { //为申请作业开辟新空间且初始化

18

DuLinkList temp=(DuLinkList)malloc(sizeof(DuLNode)); temp->data.ID=ID; temp->data.size=request; temp->data.state=Busy; DuLNode *p=block_first->next; while(p) { if(p->data.state==Free && p->data.size==request) {//有大小恰好合适的空闲块 p->data.state=Busy; p->data.ID=ID; return OK; break; } if(p->data.state==Free && p->data.size>request) {//有空闲块能满足需求且有剩余\ temp->prior=p->prior; temp->next=p; temp->data.address=p->data.address; p->prior->next=temp; p->prior=temp; p->data.address=temp->data.address+temp->data.size; p->data.size-=request; return OK; break; } p=p->next; } return ERROR; }

//-------------------- 最佳适应算法 ------------------------ Status Best_fit(int ID,int request) { int ch; //记录最小剩余空间 DuLinkList temp=(DuLinkList)malloc(sizeof(DuLNode)); temp->data.ID=ID; temp->data.size=request; temp->data.state=Busy; DuLNode *p=block_first->next; DuLNode *q=NULL; //记录最佳插入位置 while(p) //初始化最小空间和最佳位置 { if(p->data.state==Free &&

19

(p->data.size>request || p->data.size==request) ) { q=p; ch=p->data.size-request; break; } p=p->next; } while(p) { if(p->data.state==Free && p->data.size==request) {//空闲块大小恰好合适 p->data.ID=ID; p->data.state=Busy; return OK; break; } if(p->data.state==Free && p->data.size>request) {//空闲块大于分配需求 if(p->data.size-requestdata.size-request;//更新剩余最小值 q=p;//更新最佳位置指向 } } p=p->next; } if(q==NULL) return ERROR;//没有找到空闲块 else {//找到了最佳位置并实现分配 temp->prior=q->prior; temp->next=q; temp->data.address=q->data.address; q->prior->next=temp; q->prior=temp; q->data.address+=request; q->data.size=ch; return OK; } }

//----------------------- 主 存 回 收 -------------------- Status free(int ID) {

20

DuLNode *p=block_first; while(p) { if(p->data.ID==ID) { p->data.state=Free; p->data.ID=Free; if(p->prior->data.state==Free)//与前面的空闲块相连 { p->prior->data.size+=p->data.size; p->prior->next=p->next; p->next->prior=p->prior; } if(p->next->data.state==Free)//与后面的空闲块相连 { p->data.size+=p->next->data.size; p->next->next->prior=p; p->next=p->next->next; } break; } p=p->next; } return OK; }

//--------------- 显示主存分配情况 ------------------ void show() { cout<<\ cout<<\ 主 存 分 配 情 况 +++\\n\ cout<<\ DuLNode *p=block_first->next; while(p) { cout<<\分 区 号:\ if(p->data.ID==Free) cout<<\ else cout<data.ID<data.state==Free) cout<<\空 闲\ else cout<<\已分配\ cout<<\

21

p=p->next; } }

//----------------------- 主 函 数--------------------------- void main() { int ch;//算法选择标记 cout<<\计科4班 张法光 3110006015\\n\ cout<<\ 实验三 \\n\ cout<<\动态分区分配方式的模拟 \\n\ cout<<\首次适应算法\\n\ cout<<\最佳适应算法\\n\ cout<<\请选择分配算法:\ cin>>ch; Initblock(); //开创空间表 int choice; //操作选择标记 while(1) {

cout<<\ 1: 分配内存 \\n\ cout<<\ 2: 回收内存 \\n\ cout<<\ 3: 查看分配 \\n\ cout<<\ 0: 退 出 \\n\ cout<<\请输入您的操作 :\ cin>>choice; if(choice==1) alloc(ch); // 分配内存 else if(choice==2) // 内存回收 { int ID; cout<<\请输入您要释放的分区号:\ cin>>ID; free(ID); } else if(choice==3) show();//显示主存 else if(choice==0) break; //退出 else //输入操作有误 { cout<<\输入有误,请重试!\ continue; } } }

22

5、程序运行结果

首次适应算法:

23

6、结果分析与实验小结

本次实验比较难,首次最佳适应算法和对已分配分区的释放原理比较繁琐,这里同样采取双链表指针操作结构体来存储已分配分区。为了更好的实现分配和释放功能,最好采用函数对空闲分区进行排序。总得来说,主存分配和内存回收颇具锻炼价值,涉及到主存的划分,作业的首次适应算法分配内存,这些都需要深入理解和动手实践验证。

24

4 实验四 文件系统

1、实验目的:通过具体的文件存储空间的管理、文件的物理结构、目录结构和文件操作的实现,加深对文件系统内部功能和实现过程的理解。 2、预习与参考:教材中文件系统的相关知识。 3、实验要求(设计要求)

1. 要求设计一个 n个用户的文件系统,文件目录采用两级结构; 2. 对文件必须设置保护措施;

3. 至少有Create、delete、open、close、read、write等命令。

4、程序流程图

25

5、源程序清单(需附详细的注释) #include #include #include #define NULL 0

#define getpch(type,num) (type*)malloc(sizeof(type)*num)

struct ufd{ /* 第二级:用户文件目录 UFD */ char filename[10]; /* 文件名 */

char procode[3]; /* 保护码 1:读 2:写 3:执行*/ int length; /* 文件长度 */ }*p;

typedef struct ufd UFD;

struct mdf{ /* 第一级:主目录 MDF */ char name[10]; /* 用户名 */

UFD* directory; /* 文件目录指针 */ }maindir[10]; /* 用户数组 */

typedef struct mdf MDF;

struct afd{ /* 文件运行目录 */ char filename[10]; /* 文件名 */

char procode[3]; /* 保护码 1:读 2:写 3:执行*/

int rw; /* 读写指针 初始状态读:0 写:文件长度 */ }afd[5];

int usernum,opennum; /* 登陆用户数量 打开文件数量*/ int filenum[10]; /* 所有的用户目录下的文件数目*/ char username[10]; /* 当前登陆系统的用户名*/ char

command[][10]={\ /*文件操作命令*/

void login() /*用户注册,信息写入database文件*/ { int i,j;

FILE *fp; int loginum;

int creatnum[10];

printf(\注册页面=====\\n\\n\

26

printf(\请输入注册的用户数量:\ scanf(\ for(i=0;i

printf(\请输入第%d个用户名:\ scanf(\ }

for(i=0;i

printf(\请输入%s用户新建文件数(小于10):\ scanf(\ p=getpch(UFD,10); maindir[i].directory=p; for(j=0;j

printf(\请输入新建文件名:\ scanf(\

printf(\请输入要建立的文件的属性(1:读,2:写,3:执行.):\ scanf(\

printf(\请输入要构造的文件的长度:\ scanf(\ } }

fp=fopen(\

fwrite(&loginum,sizeof(int),1,fp); /* 写已注册用户数量到dat文件*/

for(i=0;i

fwrite(maindir[i].name,sizeof(char)*10,1,fp); /* 写已注册用户名到dat文件*/ }

for(i=0;i

fwrite(&creatnum[i],sizeof(int),1,fp); /* 写用户新建文件数量到dat文件*/

p=maindir[i].directory; /* UFD获得文件目录指针*/

fwrite(p,sizeof(UFD),10,fp); /* 写用户文件目录指针地址到dat文件*/ }

fclose(fp); printf(\注册完毕=====\\n\ printf(\

27

system(\ system(\}

void init() /*初始化读入login信息*/ {

int i,j; FILE *fp;

fp=fopen(\ if(fp==NULL) { printf(\警告:根目录不存在记录,请先注册用户\\n\ login(); fp=fopen(\ }

fread(&usernum,sizeof(int),1,fp); /* 读入已注册用户数量*/ for(i=0;i

fread(maindir[i].name,sizeof(char)*10,1,fp); /* 读入已注册用户名*/ p=getpch(UFD,10); maindir[i].directory=p; }

for(i=0;i

fread(&j,sizeof(int),1,fp);

filenum[i]=j; /*读入用户新建文件数量*/

p=maindir[i].directory; /*获得文件目录指针*/

fread(p,sizeof(UFD),10,fp); /*读入用户文件目录指针地址p*/ }

opennum=0; /*运行文件数*/ }

void createfile(int userid) /*新建文件*/ { system(\

char cfilename[10]; int filelen,i; char code[3];

if(filenum[userid]>=10)/*如果用户的文件已有10个*/ {

printf(\用户的文件数量已达到上限,即10个!\\n\ return ;

28

}

printf(\新建文件页面=====\\n\\n\ printf(\请输入要建立的文件名:\ scanf(\

for(i=0;i

if(strcmp((p+i)->filename,cfilename)==0) {

printf(\文件名%s已存在!\\n\ system(\ system(\ return ; } }

printf(\请输入要建立的文件的属性(1:读 2:写 3:执行):\ scanf(\

printf(\请输入要建立的文件的长度:\ scanf(\

strcpy(p[filenum[userid]].filename,cfilename); /*添加新文件名*/ strcpy(p[filenum[userid]].procode,code); /*添加保护码*/ p[filenum[userid]].length=filelen; /*添加文件长度*/ filenum[userid]=filenum[userid]+1; /*更新文件数量*/ printf(\文件建立成功!==\\n\ system(\ system(\}

void deletefile(int userid) /*删除文件*/ { system(\

char dfilename[10]; int i,j; printf(\删除文件页面=====\\n\\n\ printf(\请输入要删除的文件名:\ scanf(\

for(i=0;i

if(strcmp(p[i].filename,dfilename)==0)/*找到要删除的文件*/ {

for(j=i;j

strcpy(p[j].filename,p[j+1].filename); strcpy(p[j].procode,p[j+1].procode);

29

p[j].length=p[j+1].length; if(j==filenum[userid]-1) { strcpy(p[j+1].filename,\ strcpy(p[j+1].filename,\ p[j+1].length=0; free(p+j+1); } }

filenum[userid]--;

printf(\文件删除成功!=====\\n\ system(\ system(\ return ; } }

printf(\找不到要删除的文件!\\n\ system(\ system(\}

void openfile(int userid) /*打开文件*/ { system(\ int i;

char ofilename[10]; printf(\打开文件页面=====\\n\\n\ if(opennum>=5) {

printf(\打开超过5个文件!\\n\ return ; }

printf(\请输入要打开的文件的文件名:\ scanf(\ for(i=0;i

if(strcmp(afd[i].filename,ofilename)==0) /*文件已经打开*/ {

printf(\文件%s已打开!\\n\ return ; } }

for(i=0;i

30

开的文件*/ {

if(strcmp(p[i].filename,ofilename)==0) /*找到该文件*/ {

strcpy(afd[opennum].filename,ofilename); /*文件运行目录添加打开文件名*/

strcpy(afd[opennum].procode,p[i].procode); /*文件运行目录添加文件保护码*/

afd[opennum].rw=0; /*更新文件运行目录文件读写指针*/

opennum++;

printf(\文件%s已打开!\\n\ printf(\打开文件成功=====\\n\\n\ system(\ system(\ return ; } }

printf(\打不到要文件打开的文件,打开文件失败!\\n\ system(\ system(\}

void closefile() /*关闭文件*/ { system(\ int i,j;

char clfilename[10];

if(opennum==0) /*没有文件被打开过*/ {

printf(\当前还没有打开文件!\\n\ return ; } printf(\删除文件页面=====\\n\\n\ printf(\请输入要关闭的文件名:\ scanf(\ for(i=0;i

if(strcmp(afd[i].filename,clfilename)==0)/*在运行文件目录中找到要关闭的文件*/ {

if(afd[i].rw==1) {

printf(\文件写回磁盘!\\n\

31

}

for(j=i;j

strcpy(afd[j].filename,afd[j+1].filename); strcpy(afd[j].procode,afd[j+1].procode); afd[j].rw=afd[j+1].rw; }

opennum--;

printf(\文件%s已成功关闭!\\n\ printf(\关闭文件成功=====\\n\\n\ system(\ system(\ return ; } }

printf(\文件%s没有打开!关闭失败!\\n\ system(\ system(\}

void readfile() /*读入文件*/ { system(\ int i;

char rfilename[10];

if(opennum==0) /*没有文件被打开过*/ {

printf(\操作错误,当前还没有打开文件!\\n\ system(\ system(\ return ; } printf(\读入文件页面=====\\n\\n\ printf(\请输入要读入的文件名:\ scanf(\ for(i=0;i

if(strcmp(afd[i].filename,rfilename)==0)/*在运行文件目录中找到要读的文件*/ {

if(afd[i].procode[0]!='1')/*文件没有读权限,将不执行读操作,提示返回*/ {

32

printf(\权限不足,该文件不能读!读失败!\\n\ return ; }

printf(\文件%s已读完!\\n\ printf(\读入文件成功=====\\n\\n\ system(\ system(\ break ; } } }

void writefile() /*写出文件*/ {

system(\ int i;

char wfilename[10];

if(opennum==0) /*没有文件被打开过*/ {

printf(\当前还没有打开文件!\\n\ system(\ system(\ return ; } printf(\写出文件页面=====\\n\\n\ printf(\请输入要写的文件的文件名:\ scanf(\ for(i=0;i

if(strcmp(afd[i].filename,wfilename)==0)/*在运行文件目录中找到要关闭的文件*/ {

if(p[i].procode[1]!='1')/*文件没有写权限,将不执行写操作,提示返回*/

{

printf(\该文件不能写!写失败!\\n\ return ; }

afd[i].rw=1;

printf(\文件%s已写完!\\n\ printf(\写出文件成功=====\\n\\n\ return ; } }

33

printf(\操作错误,当前文件%s还没有打开!\\n\ system(\ system(\}

void displayinfo() /*显示所有用户目录文件信息*/ { system(\ int i,j; printf(\ for(i=0;i

printf(\用户名\\t文件名\\t保护码\\t文件长度\\n\ printf(\ for(j=0;j

printf(\e,maindir[i].directory[j].length); } }

printf(\

printf(\已经打开文件列表:\\n\\t\\t文件名\\t保护码\\t读写指针(为1表示已进行过写操作)\\n\

for(i=0;i

printf(\ } system(\ system(\}

void savefile() /*保存操作*/ {

/*开始把输入的构造信息写入到文件dat*/ int i;

FILE *fp;

fp=fopen(\ fwrite(&usernum,sizeof(int),1,fp); for(i=0;i

fwrite(maindir[i].name,sizeof(char)*10,1,fp); }

34

for(i=0;i

fwrite(&filenum[i],sizeof(int),1,fp); p=maindir[i].directory;

fwrite(p,sizeof(UFD),10,fp); }

fclose(fp);

printf(\当前目录信息已自动保存至文件database!\\n\}

void main() {

int i,j,n,userid,choose=0,quit=0; char inputname[10]; system(\ printf(\计科4班 3110006015 张法光\\n\ printf(\实验四\\n\ printf(\注册用户\\n\ printf(\登陆用户\\n\ printf(\请输入操作命令:\ scanf(\ if(n==1) { login(); /*用户注册,用户文件信息写入dat文件*/ }

init(); /*信息初始化*/ system(\ for(i=0;i

printf(\用户名\\t文件名\\t保护码\\t文件长度\\n\ printf(\ for(j=0;j

printf(\e,maindir[i].directory[j].length); } } printf(\登陆页面=====\\n\\n\ j=0;

while(j==0) {

35

printf(\请输入登录用户名:\ /*用户登陆*/ scanf(\

for(userid=0;userid

p=maindir[userid].directory; /*获得用户文件目录指针*/

printf(\用户%s目录下的文件======\\n\ for(i=0;i

printf(\ /*显示该用户文件列表*/ }

printf(\ system(\ system(\ opennum=0;

while(true) /*操作主目录*/ { j=0;

system(\

printf(\ <<文件系统演示>>\\n\

printf(\ printf(\ create 新建文件.\ printf(\ delete 删除文件.\ printf(\ open 打开文件.\ printf(\ close 关闭文件.\ printf(\ read 读出文件.\ printf(\ write 写进文件.\ printf(\ display 显示用户列表.\ printf(\ quit 安全退出.\

printf(\ printf(\操作命令:create delete open close read write display quit\\n\ printf(\请输入操作命令:\

36

scanf(\ getchar();

for(i=0;i<8;++i) { if(strcmp(command[i],inputname)==0) /*命令存在*/ { j=1;

choose=i+1; break; } }

if(j==0) { printf(\输入命令不正确!\ system(\ continue; }

switch(choose) {

case 1:

createfile(userid); break; case 2:

deletefile(userid); break;

case 3:

openfile(userid); break;

case 4:

closefile(); break;

case 5:

readfile(); break;

case 6:

writefile();

37

break;

case 7: displayinfo(); break;

case 8: quit=1; break;

default:

break; } if(quit==1)break; }

savefile(); }

6、程序运行结果

38

7、结果分析与实验小结

通过这四次实验,不由感叹这门计算机专业的课学好不仅仅是要把书上的基本知识学好而且还要不断进行实践,将所学的跟实践操作结合起来才能更好地巩固所学,才能提高自己实践能力.文件的逻辑结构和管理方法实际上并不难,关键在于对文件的结构划分和目录处理。但是若要深入发掘其中的东西,并且实际去编程实现,并不是那麼轻松,课本知识也存在局限,需要去图书馆查阅资料,也和同学讨论了很久。很高兴最后能完成实验开发,今后也需要继续学习操作系统和增加项目实践经验。

39