简单模拟操作系统中的文件操作(1)

来源:互联网 发布:网络osi的七层模型 编辑:程序博客网 时间:2024/06/13 18:26

1 实习内容

文件操作及其实现。

2 实习目的

文件系统是操作系统中管理和存取信息的机构,它具有“按名存取”的功能,不仅方便用户,而且能提高系统效率且安全可靠。

在用户程序中可使用文件系统提供的一整套文件操作(文件类系统调用),这类操作一般包括“打开文件”、“关闭文件”、“读文件”、“写文件”和“撤消文件”等。本实习模拟文件操作的实现,通过实习了解各文件操作的作用。

3 实习步骤

3.1 需求分析

模拟实现采用二级目录结构的磁盘文件系统中的文件操作。

(1) 文件系统使用文件目录来实现“按名存取”,在本实习中采用三级文件目录结构,第一级为主文件目录MFD,第二级为用户文件目录UFD,第三级为用户已打开文件目录UOF。假定系统可同时管理N个用户的文件,每个用户最多在磁盘上保存L个文件,在模拟实习中约定采用定长记录格式组织文件,那么,三级目录结构可用如下形式,如表1、表2所示:

 

 

表1 主文件目录MFD

 

用户名

用户文件目录地址

用户已打开文件目录地址

N栏

用户的UFD文件名

用户的UOF文件名

 

 

表2 用户文件目录UFD

 

文件名

文件属性

记录长度

文件地址

L栏

默认(0为只读/1为读写)

 

 

 

系统中只有一张主文件目录表,表中的每一栏与一个用户对应,从中可找到用户文件目录表和用户已打开文件目录表的存放地址。共有N张用户文件目录表,在用户文件目录表中,每一栏与一个文件对应。其中“文件属性”规定了文件的使用权限:只可读、可读可写;“记录长度”指组成该文件的逻辑记录长度;“文件地址”指文件存放在磁盘上的首块地址。为简单起见,在模拟实习中约定按MS-DOS的链接结构组织文件。

(2) 用户对文件进行存取之前,必须先提出“建立文件”或“打开文件”,系统为每个用户设置一张用户已打开文件表UOF,用以说明当前正在使用的文件的情况,如果用户最多同时打开或建立s个文件,那么,已打开文件表应该有s个登记栏。结构如表3所示:

 

表3 用户已打开文件表UOF

 

文件名

文件属性

记录长度

状态(打开/建立)

读指针

写指针

S栏

默认(0为只读/1为读写)

 

默认(0为打开/1为建立)

 

 

 

用户打开或建立一个文件时,相应的文件操作把有关该文件的信息登记到已打开文件表中,读指针和写指针用于指出对文件存取的当前位置。

 

 

3.2 数据结构设计与说明

通过上面的需求分析,我最终选定了采用结构体作为基本的数据结构,具体使用结构体的成员变量时,我通过使用数组来调用。

    (1)具体数据结构如下:

 

#define CMD   12

//命令的最大长度为CMD

#define N 6

//MFD最大为N栏

#define L 8

//UFD最大为L栏

#define S 5

//UOF最大为S栏

#define F 1000

//文件目录表FAT的最长空间

#define UNL   16

//用户名的最大长度

#define FNL   15

//文件名的最大长度

#define FAT   int

//FAT即为int

 

typedef struct MFD

{

   char user_name[UNL];

   char ufd_add[FNL];

   char uof_add[FNL];

}MFD;

//主文件目录表

typedef struct UFD

{

   char file_name[FNL];

   int file_pow;

   int record_len;

   int file_add;

}UFD;

//用户文件目录表

typedef struct UOF

{

   char file_name[FNL];

   int file_pow;

   int record_len;

   int file_sta;

   int read_p;

   int write_p;

}UOF; 

//用户已打开文件目录表

 

 

typedef struct SORT_ADD

{

   int userid;

   int fileid;

   int start_add;

   int end_add;

}SORTADD;

//此结构体是为了存储对用户文件表中的文件地址排序后的起始地址,和结束地址。

//因为在新建文件时,要找到空闲的磁盘块分配,而文件操作中对地址的管理是全局的,是不分用户的。

//所以要在分配前先对文件地址排序。

 

 

(2)本程序中定义的全局变量如下:

 

MFD main_file[N],*main_file_p;

UFD user_file[N-1][L],*user_file_p;

//[N-1]是为了排除管理员用户。

UOF user_open_file[N-1][S],*user_open_file_p;

//[N-1]是为了排除管理员用户.

FAT fat[F];

//文件目录表,fat的下标就是地址块号,块号的内容为-1表示记录结束.

SORTADD sor_add[(N-1)*L];

//因为最多有(N-1)个普通用户,L个文件,所以sor_add的大小应为(N-1)*L个.

 

struct tm *newtime;

long ltime;

int second;

//上面三句定义是为了存储当前系统时间中的秒数。

 

3.3 算法设计

(1)本程序中涉及到的成员函数:

 

int initialize_mfd();//初始化主文件目录表(从文件读取).

int initialize_ufd(int);//初始化用户文件目录表(从文件读取).

int ufd_write_uof(int);

//把ufd文件中的数据写入uof文件,构成uof的部分数据。然后利用一般赋值语句,把剩余数据初始化(往文件中写).

int initialize_uof(int);//初始化已打开文件表(从文件读取).

int initialize_fat();//初始化FAT(文件目录)表.

int output_mfd();//输出主文件目录表.

int output_ufd(int);//输出用户文件目录表.

int output_uof(int);//输出用户已打开文件目录表.

int create(int,char * ,int,int );//建立文件.

int open(int,char * ,int);//打开文件.

int read(int,char * ,int);//读文件.

int write(int,char * ,int);//写文件.

int close(int,char * );//关闭文件.

int delet(int,char * );//撤销文件.

int mypassword(char *);//实现密码的输入.

int log_in();//实现用户身份的验证.

int test_run_command(int);//实现命令的验证并运行.

int soradd();//对所有用户的所有文件的起始地址排序。

int ad_check_out();//管理员用户选择打印MFD、UFD、UOF,且对于UFD和UOF可以选择打印。

int check_out(int);//普通用户选择打印UFD和UOF,无权打印MFD。注意:普通用户只能打印自己的信息。

 

 

 

(2)下面主要针对文件操作相关的6个模块给出其总体关系及各模块的流程图、函数调用说明。如下:

 

假定文件系统提供的文件操作有,“建立文件”(create)、“打开文件”(open)、“关闭文件”(close)、“读文件”(read)、“写文件”(write)、“撤消文件”(delete)。用户要保存一个新文件时,必须顺序调用“建立文件”、“写文件”、“关闭文件”的操作,用户要读、修改、扩充一个已经保存好的文件时,必须顺序调用“打开文件”、“读/写文件”、“关闭文件”的操作。在模拟实习中可不断地从键盘输入文件操作命令来模拟各用户程序中所调用的各种文件操作。用一个结束命令(end)停止程序执行。

 

这里特别指出在对数据初始化部分,为了使数据测试的比较稳定、全面,所以我的测试数据都是从记事本文件里读取的:

具体涉及的函数如下:

int initialize_mfd();//初始化主文件目录表(从文件读取).

int initialize_ufd(int);//初始化用户文件目录表(从文件读取).

int ufd_write_uof(int);

//把ufd文件中的数据写入uof文件,构成uof的部分数据。然后利用一般赋值语句,把剩余数据初始化(往文件中写).

int initialize_uof(int);//初始化已打开文件表(从文件读取).

int initialize_fat();//初始化FAT(文件目录)表.

 

输出MFD、UFD、UOF信息的函数是:

int output_mfd();//输出主文件目录表.

int output_ufd(int);//输出用户文件目录表.

int output_uof(int);//输出用户已打开文件目录表.

但是普通用户和管理员是通过一下两个输出选择函数来选择打印什么信息:

int ad_check_out();//管理员用户选择打印MFD、UFD、UOF,且对于UFD和UOF可以选择打印。

int check_out(int);//普通用户选择打印UFD和UOF,无权打印MFD。注意:普通用户只能打印自己的信息。

也就是说上面两个函数应该调用下面3个函数:

int output_mfd();//输出主文件目录表.

int output_ufd(int);//输出用户文件目录表.

int output_uof(int);//输出用户已打开文件目录表.

 

 

一下两个函数是初始化数据后普通用户和管理员登录和输入命令并选择执行的时候用到的:

int log_in();//实现用户身份的验证.

int test_run_command(int);//实现命令的验证并运行.

 

 

注意:

管理员用户选择打印MFD、UFD、UOF,且对于UFD和UOF可以选择打印。

普通用户选择打印UFD和UOF,无权打印MFD。注意:普通用户只能打印自己的信息。

管理员只用查看MFD后,用普通用户身份登录才能对文件进行6大操作。但是管理员知道所有的用户名,所以能对所有用户的所以文件操作。

 

于是程序的序主体流程如图1所示:

 

 

图1 程序主体流程图

 

 

输入并验证命令模块:

int test_run_command(int u_num)

入口参数:在调用log_in()登录模式,会把用户名在MFD中的位置,即结构体main_file[N]的下标值作为实参传给test_run_command(u_num).参数u_num即为当前用户在MFD中的位置。

出口参数:默认 return 0;

主体程序正是通过调用int test_run_command(int u_num)来选择执行6大操作模块。

 

 

当用户想把一批信息作为一个文件存放到磁盘上以备以后使用时,首先向系统提出“建立文件”的要求,命令的一般格式如下:

int create(int num,char * fname,int rec_len,int fpow)

入口参数:当前用户在MFD中的位置num,文件名fname,记录长度rec_len,文件属性fpow

出口参数:默认 return 0;

模拟文件系统进行“建立文件”的算法如图2所示:


 

图2 创建文件流程图

 

 

用户在使用一个文件前,必须提出“打开文件”的要求。命令的一般格式为:

    int open(int num,char * fname,intoper_type)

入口参数:当前用户在MFD中的位置num,文件名fname,操作类型oper_type

出口参数:默认 return 0;

其中操作类型指出文件打开后,用户将对文件进行读操作还是写操作。文件系统必须根据文件属性核对操作的合法性,当操作类型与文件属性不符合时就不允许打开。为简单起见,在本实习中约定对处在建立状态的文件不允许打开。如图3所示:

 

 

 


 

 

图3 打开文件流程图

 

 

 

 

文件打开后就可用“读文件”操作请求顺序读文件中的若干记录,或请求读文件中的一个指定记录。约定本模拟实习中只讨论顺序读文件中若干记录的方式。于是命令的格式可为:

    int read(int num,char * fname,int read_len)

入口参数:当前用户在MFD中的位置num,文件名fname,读长度read_len

出口参数:默认 return 0;

其中读长度表示本次要读的文件记录数。模拟“读文件”操作的算法如图4所示:


                                                                                                     

图4 读文件流程图

 

 

文件系统在执行“写文件”操作时要区分两种情况。第一种情况是在执行“建立文件”操作后,用户提出“写文件”。第二种情况是在执行“打开文件”操作后,用户提出“写文件”。

由于“建立文件”操作仅完成登记注册的工作,要把信息存入磁盘,必须执行“写文件”操作,用户提出“写文件”时可要求一次只写一个记录,这时,存放一个文件需由多次“写文件”来完成,也可要求一次写一个文件,这时,需给出文件长度。约定在本模拟实习中只讨论每次顺序写一个记录的方式。

“打开文件”后,用户提出“写文件”时,文件系统认为用户对一个已经建立好的文件进行修改,扩充或插入。约定在本模拟实习中只讨论对文件进行修改的情况,可以顺序修改文件中每个记录或只修改指定的某个记录。因此,在本实习中“写文件”命令的格式可以是:

   int write(int num,char * fname,intrec_id)

入口参数:当前用户在MFD中的位置num,文件名fname,记录号rec_id

出口参数:默认 return 0;

其中记录号是指出需修改的记录编号,要求顺序写一个记录时,可省略记录号。模拟“写文件”操作的工作流程如图5所示:

 


                                                              

 

图5 写文件流程图

 

 

 

当对某个文件不再需要读或写时,用户应关闭文件,“关闭文件”的命令格式为:

int close(int num,char * fname)

入口参数:当前用户在MFD中的位置num,文件名fname

出口参数:默认 return 0;

系统进行“关闭文件”操作的工作是把文件从已打开文件表中除名。模拟算法如图6所示:

 

 

图6 关闭文件流程图

 

 

 

 

当用户不再需要一个由自己建立的文件时,可以向系统提出撤消文件的要求。“撤消文件”的一般格式为:

   intdelet(int num,char * fname)

入口参数:当前用户在MFD中的位置num,文件名fname,读长度

出口参数:默认 return 0;

系统执行“撤消文件”操作时,要将所撤消的文件在用户目录表中除名,且收回该文件所占用的存储区域,如图7所示:

 

 

图7 删除文件流程图

 

未完待续,请见下篇:简单模拟操作系统中的文件操作(2)!


本文为原创,如需使用请注明出处!