大学
操作系统课程综合实践
题目:
磁盘文件操作
班级:
姓名:
学号:
指导教师:
2011年 12 月 23日
磁盘文件操作
摘要:
为了正确地实现文件的存取,文件系统设计了一组与存取文件有关的功能模块,用户可以用“访问指令”调用这些功能模块,以实现文件的存取要求。我们把文件系统设计的这一组功能模块称为“文件操作“,实验就是要模拟实现一些文件操作。文件操作不是独立的,它和文件系统的其他部分密切相关,若要实现文件操作就离不开文件的目录结构、文件的组织结构和磁盘空间的管理。因此,这个实习虽然是文件操作的模拟实现,但还是必须模拟一部分文件的组织结构、目录结构和磁盘空间管理的实现。
关键字:磁盘、文件、目录、分配表。
一、实验内容:
设计一个简单的文件系统,用文件模拟磁盘,用数组模拟缓冲区,要求实现; 1. 2. 3. 4. 支持多级目录结构,支持文件的绝对路径;
文件的逻辑结构采用流式结构,物理结构采用链接结构中的显示链接方式;
采用文件分配表;
实现的命令包括建立目录、列目录、删除空目录、建立文件、删除文件、显示文件内容、打开文件、读文件、写文件(追加方式)、关闭文件、改变文件属性。
最后编写主函数对所做工作进行测试。
二、实验目的:
1、
2、
3、
4、文件的操作。
文件的逻辑结构和物理结构 磁盘空间的管理 磁盘目录结构
三、实验环境: Windows XP、VC++
四、程序运行结果(详图):
程序运行的主界面:用户运行命令7-建立目录
用户运行命令1-建立文件:
显示目录内容:
打开文件:
写文件:
关闭文件:
再次显示目录内容:
以上为程序的运行的部分截图。
五、程序清单: #define false 0 #define true 1 #include \"stdio.h\" //#include #include //#param warning(disable:4996) FILE*x1,*x2; typedef struct {
char name[3]; /*文件或目录名*/ char type[2]; /*文件类型名*/ char attribute; /*属性*/ char addre; /*文件或目录的起始盘块号*/ char length; /*文件长度,以盘块为单位*/ }content; /*目录结构*/ #define n 5 /*模拟实验中系统允许打开文件的最大数量*/ typedef struct { int dnum; /*磁盘盘块号*/ int bnum; /*盘块内第几项*/ }pointer; /*已打开文件表中读写指针的结构*/ typedef struct {
char name[20]; /*文件绝对路径名*/ char attribute;/*文件的属性,用1个字节表示,所以用了char类型*/ int number; /*文件起始盘块号*/ int length; /*文件长度,文件占用的字节数*/ int flag; /*操作类型,用\"0\"表示以读操作方式开文件,用\"1\"表示写操作pointer read; /*读文件的位置,文件刚打开时dnum为文件起始盘块号,bnumpointer write; /*写文件的位置,文件建立时dnum为文件起始盘块号,bnum方式打开文件*/ 为\"0\"*/ 为\"0\",打开时为文件末尾*/ }OFILE; /*已打开文件表项类型定义*/ struct {
char buffer1[64];/*模拟缓冲1*/ content buffer2[8];/*模拟缓冲2*/ FILE *fc; /*模拟磁盘的文件指针*/
void copen(OFILE *x1,OFILE *x2) //OFILE *x1,*x2; {
} strcpy(x1->name,x2->name); x1->attribute=x2->attribute; x1->number=x2->number; x1->length=x2->length; x1->flag=x2->flag; x1->read.dnum=x2->read.dnum; x1->read.bnum=x2->read.bnum; x1->write.dnum=x2->write.dnum; x1->write.bnum=x2->write.bnum; OFILE file[n]; /*已打开文件表*/ int length; /*已打开文件表中登记的文件数量*/ }openfile; /*已打开文件表定义*/
int sopen(char *name) /*在已打
开
文
件
表
中
查
找
文
件//P172 //char *name; {
void dopen(char *name) /*在已打开文件表中删除文件name*/ //char *name; {
int iopen(content *x) /*在已打开文件表中插入文件name*/ //content *x; { int i; i=sopen(name); if(i==-1) {
} copen(&openfile.file[i],&openfile.file[openfile.length-1]); openfile.length--; printf(\"文件未打开\\n\"); else int i; i=0; while(i
name*/ 依次查找已打开文件表*/ if(i>=openfile.length) return(i); }/*查找sopen函数结束*/ }/*删除函数结束*/
int i; i=sopen(x->name); if(i!=-1) {
} else if(openfile.length==n) {
} else {
} //copen(&openfile.file[openfile.length],x); openfile.length++; return(true); printf(\"已打开文件表已满\\n\"); return(false); printf(\"文件已经打开\\n\"); return(false); }/*填写已打开文件表函数结束*/ int allocate( ) /*分配一个磁盘块,返回块号*/ {
*/
//P173 int i; fseek(fc,0,SEEK_SET); /*将模拟磁盘的文件指针移至模拟磁盘FAT表*/ fread(buffer1,64L,1,fc);/*将FAT表中第一个磁盘块读入模拟缓冲for(i=3;i
} fseek(fc,0,SEEK_SET); fwrite (buffer1,64L,1,fc); return(i); /*返回磁盘号*/ fread(buffer1,64L,1,fc);/*将FAT表中第二个磁盘块读入模拟缓冲for(i=0;i
if(buffer1[i]==0) {/*FAT中的第i项为0,分配第i+64块磁盘块,修改FAT表,并且写
} printf(\"已经没有磁盘空间\\n\"); return(false); buffer1[i]=255; fseek(fc,-64L,SEEK_CUR); fwrite(buffer1,64L,1,fc); return(i+64); /*返回磁盘号*/ buffer1中*/ 回磁盘*/ }/*分配磁盘块函数结束*/ int read_file(char *name,int length) /*读文件函数,文件路径名name,读取长度length*/ //char *name; //int length; {
int i,t; //char ch; if((i=sopen(name))==-1) {
} if(openfile.file[i].flag==1) { printf(\"文件以写方式打开,不能读\\n\"); printf(\"文件没有打开或不存在\\n\"); return (false);
} return 0; t=0; fseek(fc,openfile.file[i].read.dnum*64L,SEEK_SET); fread(buffer1,64,1,fc); while(t
openfile.file[i].read.dnum=buffer1[openfile.file[i].read.dnum%64]
}
} t++; openfile.file[i].read.bnum=0; fseek(fc,openfile.file[i].read.dnum*64L,SEEK_SET); fread(buffer1,64,1,fc);/*读取下一个*/ putchar(buffer1[openfile.file[i].read.bnum]);/*读出一个字符(这if((t+1)%64==0)putchar(\'\\n\'); /*修改读指针*/ openfile.file[i].read.bnum++; if(openfile.file[i].read.bnum>=64)/*一块读完,读取下一个盘块*/ { fseek(fc,openfile.file[i].read.dnum/64*64, SEEK_SET); fread(buffer1,64,1,fc); 里是在屏幕上显示)*/ ;/*修改读指针*/ }/*读函数结束*/ int write_file(char *name,char *buff,int length) //P174 /*写文件函数*/ //char *name;/*文件路径名*/ //char *buff;/*存放准备写入磁盘的内容*/ //int length;/*写入内容的长度*/ {
int i,t,dd; if((i=sopen(name))==-1)/*文件不存在,无法写*/ {
} if(openfile.file[i].flag==0) {
} t=0; fseek(fc,openfile.file[i].write.dnum*64L, SEEK_SET); fread(buffer1,64,1,fc); while(t
buffer1[openfile.file[i].write.bnum]=buff[t]; openfile.file[i].write.bnum++; openfile.file[i].length++; if(openfile.file[i].write.bnum>=64) {
fseek(fc, openfile.file[i].write.dnum*64L, SEEK_SET); fwrite(buffer1,64,1,fc);/*一块写完,写回磁盘*/ if((dd=allocate())==false) {
openfile.file[i].write.bnum--; openfile.file[i].length--; printf(\"无磁盘空间,部分信息丢失,写失败\\n\"); return (false); printf(\"文件以读方式打开,不能写\\n\"); return (false); printf(\"文件没有打开或不存在\\n\"); return (false); }/*if*/ fseek(fc,openfile.file[i].write.dnum/64*64L, SEEK_SET); fread(buffer1,64,1,fc); buffer1[openfile.file[i].write.dnum%64]=dd; fseek(fc,openfile.file[i].write.dnum/64*64L, SEEK_SET);
fwrite(buffer1,64,1,fc); openfile.file[i].write.dnum=dd; openfile.file[i].write.bnum=0; }/*if*/ t++; }/*while*/ fseek(fc, openfile.file[i].write.dnum*64L, SEEK_SET); fwrite(buffer1,64,1,fc);/*一块写完,写回磁盘*/ }/*写函数结束*/ int search(char *name,int flag,int *dnum,int *bnum) /*查找路径名为name的文件或目录,返回该目录的起始盘块号 */ //char *name; //int flag; /*flag=8表示查找目录,否则为文件*/ //int *dnum,*bnum;/*返回找到文件或目录的目录项的位置:盘块dnum中第bnum项*/ {
for(s=0;name[k]!=\'.\'&&name[k]!=\'/\'&&s
pna[s]=name[k]; pna[s]=\' \'; for(;s
根
目
录
*/ //P175 k=0; if(name[0]==\'/\')k=1; i=2; /*i=根目录的起始盘块号*/ while(last!=1) { /*pna=从name中分离出\"/\"后一个目录名(或文件名)*/ */
&
while(name[k]!=\'.\'&&name[k]!=\'\\0\'&&name[k]!=\'/\')/*除去多余字符 k++; type[0]=type[1]=\' \'; if(name[k]==\'.\')/*取文件类型名type*/
if(flag==8) {
} else {/*文件遇到类型名认为结束,后面的字符作废*/
} else
if(name[k]!=\'\\0\')k++; if(name[k]==\'\\0\') last=1; /*查找目录且名字等于pna的目录项*/ fseek(fc,i*64L,SEEK_SET); fread(buffer2,64L,1,fc); j=0; if(last==1&&flag!=8) k++; if(name[k]!=\'\\0\')type[0]=name[k]; k++; if(name[k]!=\'\\0\')type[1]=name[k]; if(name[k]!=\'\\0\'&&name[k+1]!=\'\\0\') {
} last=1; printf(\"文件名错误\\n\"); return(false); printf(\"目录不应该有有类型名,查找失败\\n\"); return(false); while(j
j++; buffer2[j].name[1]==pna[1]&&buffer2[j].name[2]==pna[2]&& buffer2[j].type[0]==type[0]&&buffer2[j].type[1]==type[1])) else while(j
&&buffer2[j].name[2]==pna[2])) j++;
if(last==1)/*查找结束*/ {
*dnum=i; *bnum=j;
return(buffer2[j].addre); &buffer2[j].name[1]==pna[1]
if(j
} else/*查找还未结束*/
i=buffer2[j].addre;/*读取下一个盘块*/ return(false); else //P176 }/*while 查找结束*/ }/*search()结束*/ int create_file(char *name,int attribute) /*建立文件函数,路径名name,文件属性attribute*/ //char *name; //int attribute; { int i,j,k,s,d,t,b,dd,dn,bn; char dname[3],tname[2],pathname[20];
OFILE x; if(attribute%2==1) {
} if(openfile.length==n) {
} /* 将name分成两部分,目录路径pathname和目录名dname*/ for(j=0;name[j]!=\'\\0\';j++)/*查找最后一个“/”*/
if(name[j]==\'/\')s=j; /*分离目录路径*/ for(j=0;j
} for(;k
} for(;k
tname[k]=\' \'; if((d=search(pathname,8,&dn,&bn))==false)/*找到目录路径,返回该{
} /*确认该目录不存在的同时查找空目录项*/ printf(\"目录不存在,不能建立\"); return(false); 目录所在块号dn和项数bn*/ b=-1; fseek(fc,d*64L,SEEK_SET); fread(buffer2,64L,1,fc); /*读出dnum盘块的内容*/ for(t=0;t
{/*找到名字dname的文件,建立失败*/
} if(buffer2[t].name[0]==\'$\'&&b==-1) b=t; printf(\"文件已经存在,不能建立\\n\"); return(false); ffer2[t].name[2]==dname[2] &&buffer2[t].type[0]==tname[0]&&buffer2[t].type[1]==tname[1]) }/*for*/ if(b==-1)/*没有空目录项,建立失败*/ {
} if((dd=allocate( ))==false)/*分配给建立目录的磁盘盘块dd*/ { printf(\"建立文件失败\\n\"); return(false); printf(\"目录无空间\\n\"); return(false);
} /*填写目录项*/ for(i=0;i
OFILE x; int dnum,bnum,last,i,d; if((d=search(name,4,&dnum,&bnum))==false) {
} printf(\"文件不存在,打开操作失败\\n\"); return(false);
} fseek(fc,dnum*64L,SEEK_SET);/*fread(buffer2,64,1,fc);
读出对应目录项*/ //P178 if((buffer2[bnum].attribute%2==1)&& attribute==1)/*对只读文件要求{
} strcpy(x.name,name); x.attribute=buffer2[bnum].attribute; x.number=buffer2[bnum].addre; x.read.dnum=x.write.dnum=buffer2[bnum].addre; x.read.bnum=x.write.bnum=0; x.flag=attribute; if(attribute==1) {
} iopen(&x);/*填写已打开文件表*/ while(d!=\'\\xff\')/*寻找文件末尾*/ {
fseek(fc, d/64*64L, SEEK_SET); fread(buffer1,64L,1,fc);/*读出dnum项所在FAT*/ last=d; d=buffer1[d%64];/*读出dnum块下一块内容赋给dnum*/ printf(\"文件不能写,打开失败\"); return(false); 写*/ }/*while*/ x.write.dnum=last;/*填写写指针*/ fseek(fc, last*64L, SEEK_SET); fread(buffer1,64L,1,fc); for(i=0;i
}
int Delete(char *name) /*删除文件*/ //char *name; int i,dnum,bnum; if((i=sopen(name))==-1) {
} if(openfile.file[i].flag==1)/*写文件的追加文件结束符*/ {
} /*在已打开文件表中删除该文件的登记项*/ fseek(fc,openfile.file[i].write.dnum*64L, SEEK_SET); fread(buffer1,64,1,fc); buffer1[openfile.file[i].write.bnum]=\'#\'; fseek(fc,openfile.file[i].write.dnum*64L, SEEK_SET); fwrite(buffer1,64,1,fc); fputc(\'#\',fc); search(name,4,&dnum,&bnum);/*查找该文件目录位置*/ /*修改目录中的文件长度*/ fseek(fc,dnum*64L, SEEK_SET); fread(buffer2,64,1,fc); buffer2[bnum].length=openfile.file[i].length/64+1; fseek(fc, dnum*64L, SEEK_SET); fwrite(buffer2,64,1,fc); printf(\"打开的文件中没有该文件,关闭失败\\n\"); return(false); if(openfile.length>1) copen(&openfile.file[i],&openfile.file[openfile.length-1]); //P179 openfile.length--; {
int md(char *name) /*建立目录函数,目录路径名name*/ //char *name; { int i,j,k,s,d,t,b,dd,dn,bn; int dnum,bnum,t; if((t=search(name,4,&dnum,&bnum))==false) {
} if(sopen(name)!=-1) {
} fseek(fc,dnum*64L, SEEK_SET); fread(buffer2,64,1,fc); buffer2[bnum].name[0]=\'$\';/*将该文件的目录置成空目录*/ fseek(fc,dnum*64L, SEEK_SET); fwrite(buffer2,64,1,fc); while(t!=\'\\xff\')/*通过FAT查找每一个盘块号,并依次删除*/ {
} dnum=t; fseek(fc, dnum/64*64, SEEK_SET); fread(buffer1,64,1,fc); t=buffer1[dnum%64]; buffer1[dnum%64]=0; fseek(fc, dnum/64*64L, SEEK_SET); fwrite(buffer1,64,1,fc); printf(\"该文件打开,不能删除\\n\"); return(false); printf(\"文件不存在\\n\"); return(false); }/*文件删除结束*/
char dname[3],pathname[20]; i=2;/* i=根目录的起始盘块号*/ /* 将name分成两部分,目录路径pathname和目录名dname*/ for(j=0;name[j]!=\'\\0\';j++)/*查找最后一个“/”*/
if(buffer2[t].name[0]==dname[0]&&buffer2[t].name[1]==dname[1]
&&buffer2[t].name[2]==dname[2]&&buffer2[t].attribute==8) if(name[j]==\'/\')s=j; /*分离目录路径*/ for(j=0;j
} for(;k
} b=-1; /*确认该目录不存在的同时查找空目录项*/ fseek(fc,d*64L,SEEK_SET); fread(buffer2,64L,1,fc);/*读出d盘块的内容*/ for(t=0;t
{/*找到名字dname的目录,建立失败*/
} if(buffer2[t].name[0]==\'$\'&&b==-1) b=t; printf(\"目录已经存在,不能建立\\n\"); return(false); }/*for*/ if(b==-1)/*没有空目录项, 不能建立*/ {
} if((dd=allocate( ))==false)/*分配给建立目录的磁盘盘块dd*/ {
} /*填写目录项*/ for(i=0;i
int t,dnum,dn,bn; if((dnum=search(name,8,&dn,&bn))==false)/*找到目录路径,返回该目录{
} printf(\"目录不存在\\n\"); return(false); 所在块号dn和盘块内项数bn*/ printf(\"名称 扩展名 起始盘块 长度\\n\"); /*显示目录内容*/ fseek(fc,dnum*64L, SEEK_SET); fread(buffer2,64L,1,fc); for(t=0;t
if(buffer2[t].name[0]!=\'$\') printf(\" %c%c%c %c%c %4d%7d\\n\", buffer2[t].name[0], buffer2[t].name[2],
buffer2[t].type[0], //P181 buffer2[t].name[1], buffer2[t].type[1],buffer2[t].addre, buffer2[t].length); }/*显示目录函数结束*/
char typefile(char *name) /*显示文件内容*/ //char *name; {
int dnum,dn,bn,t; if((dnum=search(name,1,&dn,&bn))==false) {
} if(sopen(name)!=-1) { printf(\"文件不存在\\n\"); return(false);
} printf(\"该文件打开,不能显示\\n\"); return(false); while(dnum!=\'\\xff\') {
} fseek(fc,dnum*64L,SEEK_SET); fread(buffer1,64,1,fc);/*读一个盘块到缓冲*/ for(t=0;t
int dnum,bnum; if(search(name,1,&dnum,&bnum)==false)/*查找文件目录*/ {
} if(sopen(name)!=-1) {
} fseek(fc,dnum*64L,SEEK_SET); printf(\"该文件打开,不能改变文件属性\\n\"); return(false); printf(\"文件不存在\\n\"); return(false); //P182
fread(buffer2,64,1,fc);/*读出该目录所在盘块*/ buffer2[bnum].attribute=attribute;/*修改属性*/ fseek(fc,dnum*64L,SEEK_SET); fwrite(buffer2,64,1,fc);/*写回磁盘*/ }/*改变文件属性函数结束*/ int main( ) {
char name[20]; //FILE*x1,*x2; //errno_t err; //char err; int attribute,type,length,i,a,j; char buffer[64]; /*建立文件,模拟磁盘*/ if((fc=fopen(\"c:\\c\",\"w+\"))==NULL)// {
} /*初始化已打开文件表*/ openfile.length=0; /*初始化磁盘*/ /*初始化文件分配表*/ buffer1[0]=buffer1[1]=buffer1[2]=255;/*磁盘第0、1块存放FAT表,第for(i=3;i
fwrite(buffer1,64L,1,fc); /*初始化根目录*/ for(i=0;i
while(1) {
printf(\"\\n 0建立文件\\n\"); printf(\" 2读文件\\n\"); printf(\" 4关闭文件\\n\"); printf(\" 6建立目录\\n\"); printf(\" 8显示文件内容\\n\"); printf(\" 10 - 改变文件属性\\n\"); printf(\" 选择功能项(0~9):\"); scanf(\"%d\",&a); switch(a) { case 0: /*a=0程序结束*/
fclose(fc); exit(0); printf(\"输入文件路径名和文件属性(1-只读文件,3-只读系统文scanf(\"%s%d\",name,&attribute); create_file(name,attribute); /*建立文件*/ break; case 1: /*a=1建立文件*/ 件,4-普通文件):\"); case 2: /*a=2打开文件*/
printf(\"输入文件路径名和操作类型(0-读文件,1-写文件):\");
scanf(\"%s%d\",name,&type);
open_file(name,type); /*打开文件*/
break;
case 3: /*a=3读文件*/
printf(\"输入文件路径名和读长度\");
scanf(\"%s%d\",name,&length);
read_file(name,length); /*读文件*/
break;
case 4: /*a=4写文件*/
printf(\"输入文件路径名:\");
scanf(\"%s\",name);
printf(\"输入写的内容和和写长度\");
scanf(\"%s%d\",buffer,&length);
write_file(name,buffer,length); /*写文件*/
break;
case 5:
/*a=
5关
闭
文//P184
printf(\"输入文件路径名\");
scanf(\"%s\",name);
close_file(name); /*关闭文件*/
break;
case 6: /*a=6删除文件*/
printf(\"输入文件路径名\");
scanf(\"%s\",name);
Delete(name); /*删除文件*/
break;
case 7: /*a=7建立目录*/
printf(\"输入目录路径名\");
scanf(\"%s\",name);
md(name); /*建立目录*/
break;
case 8: /*a=8显示目录*/
printf(\"输入目录路径名\"); scanf(\"%s\",name);
件
*/
dir(name); /*显示目录*/ break; printf(\"输入文件路径名\"); scanf(\"%s\",name); typefile(name); /*显示文件*/ break; printf(\"输入文件路径名和文件属性(1-只读文件,3-只读系统文scanf(\"%s%d\",name,&attribute); change(name,attribute); case 9: /*a=9显示文件*/ case 10:/* a=10改变文件属性 */ 件,4-普通文件):\"); }/* switch */
)
结
束}/* while */ }/*main( //P185
六、结束语:
*/
通过对磁盘文件操作,使我了解了基本的磁盘文件的知识,再加上对程序流程的理解,更加明白了Windows对磁盘管理的方式,首先程序查找绝对路径名name,然后从name中分离出“/”后下一个目录(或文件名);若是文件,分离出类型名type,再进行之后的判断操作。当在已打开的文件表中查找某文件时,首先查找文件路径名为pname的文件,通过一个变量的判断,进行查找。将某文件从已打开的表中删除时,在已打开的文件表中查找路径名为name的登记项i,如果找到该文件登记项i,删除第i项,如果没有找到,提示文件没有打开,删除失败。通过对这些流程的理解,让我深刻的体会到了磁盘文件操作的步骤,达到了实习目的。 参考文献:
[1] 滕艳平等.计算机操作系统(实验指导书),哈尔滨工业大学出版社.2008年9月
[2] 张明等编.操作系统习题解答与实验指导(第二版).中国铁道出版社.2007年12月
[3] 张丽芬等编.操作系统实验教程.清华大学出版社.2006年 [4] 张献忠等编.操作系统学习辅导.清华大学出版社.2004年
[5] 汤小丹等编.计算机操作系统.西安电子科技大学出版社.2006年9月