一、实验目的
1、熟悉Linux文件系统的文件和目录结构,把握Linux文件系统的基本特点;
2、模拟实现Linux文件系统的简单I/O流操作:备份文件。
二、实验环境
Ubuntu20.10、gcc编译器
三、实验内容
1、浏览Linux系统根目录下的子目录linux文件相关命令,熟悉每位目录的文件和功能;
2、设计程序模拟实现Linux文件系统的简单I/O流操作:备份文件。
四、实验要求
1、对文件系统命令和库函数要提早熟悉;
2、画出备份文件的过程图;
3、测试数据文件提早打算好;
4、编写程序并调试;
5、截屏输出实验结果;
6、根据实验结果与理论课述说的原理进行实验剖析。
五、实验原理实验中用到的系统调用函数(包括实验原理中介绍的和自己采用的),实验步骤实验原理:
1、Linux各类发行版的目录结构基本一致,各个目录简单介绍如下:
2、Linux的文件结构是单个的树形结构.可以用tree进行展示。文件操作命令见附表1,
3、Linux文件系统:Linux中容许诸多不同的文件系统共存,如ext2,ext3,vfat等。通过使用同一套文件I/O系统调用即可对Linux中的任意文件进行操作而无需考虑其所在的具体文件系统格式;更进一步,对文件的操作可以跨文件系统而执行。“一切皆是文件”是Unix/Linux的基本哲学之一。除了普通的文件,目录、字符设备、块设备、套接字等在Unix/Linux中都是以文件被对待;它们似乎类型不同,并且对其提供的却是同一套操作界面。
4、虚拟文件系统(VirtualFileSystem,简称VFS),是Linux内核中的一个软件层,用于给用户空间的程序提供文件系统插口;同时,它也提供了内核中的一个具象功能,容许不同的文件系统共存。系统中所有的文件系统不但依赖VFS共存,并且也借助VFS协同工作。为了才能支持各类实际文件系统,VFS定义了所有文件系统都支持的基本的、概念上的插口和数据结构;同时实际文件系统也提供VFS所期望的具象插口和数据结构,将自身的例如文件、目录等概念在方式上与VFS的定义保持一致。换句话说,一个实际的文件系统想要被Linux支持,就必须提供一个符合VFS标准的插口,能够与VFS协同工作。实际文件系统在统一的插口和数据结构下隐藏了具体的实现细节,所以在VFS层和内核的其他部份看来,所有文件系统都是相同的。
5、利用C库函数fopen(),fread(),fwrite(),fclose()来实现简单的文件备份,将要一个文件的内容拷贝到另一个文件中去。
实验中用到的系统调用函数:
open(),read(),write(),close()
实验步骤:
熟悉文件系统命令:
熟悉系统调用函数open(),read(),write(),close():
熟悉C库函数fopen(),fread(),fwrite(),fclose():
画出备份文件的过程图:
两种方式备份文件的方式都是一样的,所以下边这个流程图对这两个方式都适用:
六、实验结果剖析(截屏的实验结果,与实验结果对应的实验剖析)
1、实验结果与实验程序、实验步骤、实验原理、操作系统原理的对应剖析;
2、不同条件下的实验结果反应的问题及缘由;
3、实验结果的算法时间、效率、鲁棒性等性能剖析。
浏览Linux系统根目录下的子目录,熟悉每位目录的文件和功能:
根目录下的所有文件:
/bin:
/boot:
/dev:
/etc:
/home:
/lib:
/media:
/mnt:
/opt:
/proc:
/root:
(难以访问)
/sbin:
/tmp:
/usr:
/srv:
(文件夹为空)
设计程序模拟实现Linux文件系统的简单I/O流操作:备份文件:
备份的文件储存在目录"/home/prince/file.txt"中,文件内容如图所示:
(不放图了,由于是在新华网随意复制的一篇文章,放图上来居然能被辨识到)
分别使用系统调用函数和C库函数对这个文件进行备份linux文件相关命令,备份文件名分别为backup1.txt和backup2.txt,运行程序,结果如图所示:
打开文件backup1.txt和backup2.txtlinux空间,对比上面的内容:
(也不放图了,理由同上)
七、实验数据及源代码(中学生必须递交自己设计的程序源代码,并有注释,源代码电子版也一并递交),包括思索题的程序。
程序源代码:
#include
#include
#include
#include
#include
#include
#include
const char* source = "/home/prince/file.txt"; //需要备份的源文件路径
//使用系统调用函数open(),read(),write(),close()
void backup1(){
int src,dest,size;
char str[128];
src = open(source,O_RDONLY);
dest = open("/home/prince/backup1.txt", O_WRONLY | O_CREAT); //写文件,如果文件不存在则创建
if(src == -1){
printf("src文件打开失败n");
return;
}
if(dest == -1){
printf("dest文件打开失败n");
close(src);
return;
}
while((size = read(src,str,sizeof(str)))){
write(dest,str,size);
}
close(src);
close(dest);
printf("源文件file.txt已经成功备份,备份文件为backup1.txtn");
}
//使用c库函数fopen(),fread(),fwrite(),fclose()
void backup2(){
char str[128];
FILE *src, *dest;
int size;
src = fopen(source,"r");//读取源文件
dest = fopen("/home/prince/backup2.txt","w");
if(!src){
printf("src 打开文件失败!n");
return;
}
if(!dest){
printf("dest 打开文件失败!n");
fclose(src);
return;
}
//循环读取内容,直到读取到文件结尾
while((size = fread(str,sizeof(char),128,src))){
//printf("%d %sn",size, str);
fwrite(str,sizeof(char),size,dest);
}
fclose(src);
fclose(dest);
printf("源文件file.txt已经成功备份,备份文件为backup2.txtn");
}
int main(){
backup1();
backup2();
return 0;
}
八、思考题:
1、使用系统调用函数open(),read(),write(),close()实现简单文件备份的原理是哪些?
答:
①系统调用open()函数,指定一个文件路径,则会返回一个小于0的文件描述词,假如返回值为-1代表打开文件失败。这个文件描述词可以被read()/write()和其他的系统调用函数使用。
②使用read()函数,可以向文件描述词fd对应的文件中读取size个字节的数据,并将数据存入缓冲区ptr中
③使用write()函数,可以将缓冲区ptr里前size个字节的数据写入文件描述词fd对应的文件中
④使用close()函数,可以关掉该文件,释放资源
2、使用C库函数fopen(),fread(),fwrite(),fclose()来实现简单文件备份的原理是哪些?
答:
①C库函数fopen(),可以按照指定的文件路径,读取文件linux 输入法,并把文件保存在FILE中
②fread()函数可以在stream对应的文件中读取sizenmemb个字节的数据存入缓冲区ptr中
③fwrite()函数可以往stream对应的文件中写入缓冲区ptr中前size*nmemb个字节的数据
④fclose()函数,可以关掉指定的流,释放资源
3、上述两者的区别在那里?
答:从功能上看,上述两者并无差异,在代码实现上也十分地相像,而且在原理上,上述两者具有以下差异:
①open(),read(),write(),close()为系统调用函数,执行的时侯必须从用户模式切换到内核模式,执行完毕后,再从内核模式切换到用户模式
②fopen(),fread(),fwrite(),fclose()为C库函数,只在用户态调用和执行
③系统调用函数由于须要在用户态和内核态之间来回切换,所以特别影响系统的性能,可以在一次系统调用中尽可能多地完成工作,以达到降低系统调用次数的目的,进而降低花销。前者比后者的效率要高好多。
④前者是系统函数,不可移植,在不同的操作系统上系统调用函数是不同的,而前者是标准C库函数,是可以移植的,所以在不同的操作系统上都是相同的。