操作系统实验四——系统文件

广州大学学生实验报告

开课学院及实验室:计算机科学与网络工程学院 软件实验室 202362

学院

计算机科学与网络工程学院

年级/专业/

姓名

学号

 

实验课程名称

操作系统实验

成绩

实验项目名称

系统文件

指导老师

实验  系统文件

一、实验目的

1、熟悉Linux文件系统的文件和目录结构,掌握Linux文件系统的基本特征;

2、模拟实现Linux文件系统的简单I/O流操作:备份文件。

二、实验环境

WSL-Ubuntu-18.04、gcc编译器

三、实验内容

1、浏览Linux系统根目录下的子目录,熟悉每个目录的文件和功能;

2、设计程序模拟实现Linux文件系统的简单I/O流操作:备份文件。

四、实验原理实验中用到的系统调用函数(包括实验原理中介绍的和自己采用的),实验步骤

1、实验原理:

Linux文件系统:Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等。通过使用同一套文件 I/O 系统 调用即可对 Linux 中的任意文件进行操作而无需考虑其所在的具体文件系统格式;更进一步,对文件的 操作可以跨文件系统而执行。“一切皆是文件”是 Unix/Linux 的基本哲学之一。不仅普通的文件,目录、字符设备、块设备、 套接字等在 Unix/Linux 中都是以文件被对待;它们虽然类型不同,但是对其提供的却是同一套操作界面。

虚拟文件系统(Virtual File System, 简称 VFS),是Linux内核中的一个软件层,用于给用户空间的程序提供文件系统接口;同时,它也提供了内核中的一个抽象功能,允许不同的文件系统共存。系统中所有的文件系统不但依赖VFS共存,而且也依靠VFS协同工作。为了能够支持各种实际文件系统,VFS 定义了所有文件系统都支持的基本的、概念上的接口和数据结构;同时实际文件系统也提供 VFS 所期望的抽象接口和数据结构,将自身的诸如文件、目录等概念在形式上与VFS的定义保持一致。换句话说,一个实际的文件系统想要被Linux支持,就必须提供一个符合VFS标准的接口,才能与VFS协同工作。实际文件系统在统一的接口和数据结构下隐藏了具体的实现细节,所以在VFS层和内核的其他部分看来,所有文件系统都是相同的。

2、系统调用函数:

fopen(“source.dat”,“r”);  //打开一个文件,以只读文件形式。

fread();  //读取数据从一个文件到buff中,

fwrite();  //把数据从buff中写入另一个文件

fclose();  //关闭文件

3、C库函数

int open(char *path,int flags,mode_t mode);  //参数path 是指向所要打开的文件的路径名指针。参数falgs 规定如何打开该文件它必须包含以下三个值之一,O_RDONLY只读打开,O_WRONLY只写打开,O_RDWR读/写打开,参数mode规定对该文件的访问权限,定义在<sys/stst.h>中。

int read(int fd,void *buf,size_t nbytes);  //该系统调用从文件描述符fd所代表的文件中读取nbytes 个字节,buf指定的缓冲区内。所读取的内容从当前的读/写指针所指示的位置开始,这个位置由相应的打开文件描述中的偏移值(off_set)给出,调用成功后文件读写指针增加实际读取的字节数。

int write(int fd,void *buf,size_t nbytes);  //该调用从buf所指的缓冲区中将nbytes 个字节写到描述符fd所指的文件中。

int close(int fd);  //每打开一个文件,系统就给文件分配一个文件描述符,同时为打开文件描述符的引用计数加1。Linux文件系统最多可以分配255个文件描述符。当调用close()时,打开文件描述符的引用计数值减1,最后一次对close()的调用将使应用计数值为零。

4、使用的命令:

cd命令:用来切换当前目录至别的地方。例如,cd  /表示进入系统根目录。cd ../表示进行目录回退。   

ls命令:用来查看用户有执行权限的任意目录中的文件列表。

sudo命令:全称,super user do。通过此命令,可以让一些非root用户运行只有root才有权限执行的命令。sudo最常用的功能就是提升一个命令的执行权限。

chmod命令:全称,change mode。通过此命令,可以设置用户对文件的权限。

gcc 文件名.后缀 -o文件名:对程序进行编译。

./文件名:对程序进行执行操作。

5、备份文件过程图:

五、实验结果分析(截屏的实验结果,与实验结果对应的实验分析)

(一)实验结果与实验程序、实验步骤、实验原理、操作系统原理的对应分析;

(二)不同条件下的实验结果反应的问题及原因;

(三)实验结果的算法时间、效率、鲁棒性等性能分析。

1、浏览Linux系统根目录下的子目录,熟悉每个目录的文件和功能

①使用命令cd / 打开Linux系统根目录下的子目录,并使用ls命令打印该目录下的所有文件。

②使用命令cd bin 打开该目录中的bin文件,并使用ls命令打印该文件的内容。

③使用cd boot打开该目录中的boot文件,并使用ls命令打印该文件中的内容。

④使用cd dev打开该目录中的dev文件,并使用ls命令打印该文件中的内容。

⑤使用cd etc打开该目录中的etc文件,并使用ls命令打印该文件中的内容。

⑥使用cd home打开该目录中的home文件,并使用ls命令打印该文件中的内容。

⑦使用cd lib打开该目录中的 lib 文件,并使用ls命令打印该文件中的内容。

⑧使用cd lost+found打开该目录中的文件,并使用ls命令打印该文件中的内容。

打印内容出错。原因:LOST+FOUND文件是存储发生以外后丢失的文件的,只有root用户才能打开。其它用户权限不足。

解决:

  1. sudo +原来的指令,结果:出错。但并不是所有的指令都可以用sudo,这里直接使用语句sudo lost+found还是显示错误。

2、使用语句:sudo chmod -R 777 lost+found;其中,-R 是指级联应用到目录里的所有子目录和文件777 是所有用户都拥有最高权限

正确运行结果:

2、设计程序模拟实现Linux文件系统的简单I/O流操作:备份文件

编译并运行文件lab4.c,运行结果如上图所示:

生成的备份文件如下图所示:

双击打开CopyFile1.txt,出错,如下图所示:

原因:通过系统调用函数来进行备份文件后产生的文件是无法打开的。

双击打开CopyFile2.txt,结果如下图所示:

其内容与备份源文件file.txt的内容相同。

在执行过一次文件备份后,接着再进行备份文件,就会报目标文件打开失败的错误,如下图所示:

猜想这是权限不足的原因。

解决方法:执行sudo chmod -R 777 CopyFile1.txt,授予最高权限。

然后再次进行文件备份时,就不会发生文件打开错误了。

运行结果如下图所示:

六、实验总结

(一) 实验思考题的回答

1、使用系统调用函数open(),read(),write(),close()实现简单文件备份的原理是什么?

①在进行系统调用open()函数时,需要指定一个有效的文件路径,该函数用于打开指定路径下的文件,并返回一个大于0的文件描述符,表示文件打开成功。该文件描述符可以被其他系统调用函数使用,如read()函数和write()函数等。当open()函数返回值为-1时,表示打开文件失败,一般是由于文件不存在、权限不足或者其他文件系统错误引起。

②系统调用read()函数是用于从指定文件描述符对应的文件中读取指定数量的数据,并将其存储到指定的内存缓冲区中。该函数使用时需要传入文件描述符、读取数据的大小以及指向缓冲区的指针等参数。当读取成功时,read()函数返回实际读取的字节数;当读取失败时,返回-1并设置errno标志,以便用户进一步处理错误。

③系统调用write()函数是用于将指定内存缓冲区中的数据写入到指定文件描述符对应的文件中。该函数使用时需要传入文件描述符、写入数据的大小以及指向缓冲区的指针等参数。当写入成功时,write()函数返回实际写入的字节数;当写入失败时,返回-1并设置errno标志,以便用户进一步处理错误。

④系统调用close()函数是用于关闭指定文件描述符对应的文件,并释放相关资源。该函数使用时需要传入文件描述符参数,用于指定需要关闭的文件。当关闭成功时,close()函数返回0;当关闭失败时,返回-1并设置errno标志,以便用户进一步处理错误。

2、用C库函数fopen(), fread(), fwrite(), fclose() 来实现简单文件备份的原理是什么?

①通过调用C库函数fopen(),可以实现以指定的文件路径打开文件,并进行读取操作,同时可以将文件备份到指定的备份文件中。

②fread()函数是C标准库中提供的文件读取函数,可以从指定的文件流中读取指定数量的数据,并将其存储到指定的缓冲区中。

③fwrite()函数是C标准库中提供的文件写入函数,可以将指定缓冲区中的数据写入到指定的文件流中,写入数据的大小由参数size和nmemb指定。

④fclose()函数是C标准库中提供的文件流关闭函数,可以关闭指定的文件流,并释放相关的资源。

上述四个函数的实现均依赖于操作系统提供的文件IO系统调用函数,通过调用这些函数,实现对原始文件对文件读取和备份、对文件的读取、对文件的写入以及对文件流的关闭操作。

3、上述二者的区别在哪里?

①open(), read(), write(), close()是操作系统提供给用户程序的系统调用函数,这些函数需要在用户态和内核态之间进行切换来执行,这种切换过程会对系统的性能产生一定的影响。因此,在使用这些函数时需要注意其对系统性能的影响,并进行优化。

②fopen(), fread(), fwrite(), fclose()是C语言标准库提供的函数,这些函数只能在用户态中调用和执行,不需要进行用户态和内核态之间的切换。因此,这些函数的执行效率比系统调用函数要高很多。

③由于系统调用函数需要在用户态和内核态之间来回切换执行,因此其执行效率相对较低,对系统性能的影响也相对较大。而C库函数的执行效率比系统调用函数要高,因此在编写程序时应尽可能地使用C库函数,以提高程序的执行效率和系统的性能。

④系统调用函数的具体实现方式在不同的操作系统中可能会有所不同,因此这些函数在不同的操作系统上的移植性较差。而C库函数是标准化的函数库,这些函数在不同的操作系统中都有相同的实现方式和接口规范,因此具有很好的移植性。

以上是它们原理上的区别,它们在功能上并无区别。

(二)个人总结

1、在本次实验中,我通过实验步骤一明白了文件权限的含义,通过这个实例,我上网搜集了解决文件权限不足的方法,通过执行sudo chmod -R 777 目标文件,就可以授予文件最高权限,从而可以对该文件进行读写操作。

2、本次实验中的文件备份采用库函数或者采用系统调用函数,它们在代码书写上并没有展示出较大的区别,但是其中深层中它们的效率是不同的。作为程序员,我们应该考虑到代码实现的效率。

七、实验数据及源代码(学生必须提交自己设计的程序源代码,并有注释,源代码电子版也一并提交),包括思考题的程序。

注意:   实验报告文件名   学号-姓名-实验1-班级

         实验数据与源代码 一个压缩包,名字和实验报告规则一样,需要有一个说明文件解释各个文件是什么文件。  

测试数据文件:file.txt   其目录为/home/pan/file.txt

#include<iostream>

using namespace std;

int main()

{

cout<<"hello world!"<<endl;

}

使用系统调用函数备份出的文件:CopyFile1.txt  其目录为:/home/pan/CopyFile1.txt

#include<iostream>

using namespace std;

int main()

{

cout<<"hello world!"<<endl;

}

使用库函数备份出的文件:CopyFile2.txt  其目录为:/home/pan/CopyFile2.txt

#include<iostream>

using namespace std;

int main()

{

cout<<"hello world!"<<endl;

}

代码源程序: lab4.c  其目录为/home/pan/lab4.c

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

const char* source = "/home/pan/file.txt"; //需要备份的源文件的路径

//使用系统调用函数open(),read(),write(),close()

void Copy1() {

    int sourceFlag, destinationFlag, size;

    char str[128];

    sourceFlag = open(source, O_RDONLY);//打开需要备份的文件,只读。返回文件描述符

    destinationFlag = open("/home/pan/CopyFile1.txt", O_WRONLY | O_CREAT); //文件存在,则可以打开文件进行写操作;文件不存在,则创建文件再打开该文件进行写操作

    if (sourceFlag == -1) {                                                //刚开始这个文件没有权限打开

        printf("Source file open failed!\n");

        return;

    }

    if (destinationFlag == -1) {

        printf("Destination file open failed!\n");

        close(sourceFlag);

        return;

    }

    while ((size = read(sourceFlag, str, sizeof(str)))) {  //read()用于从指定文件描述符对应的文件file.txt中读取指定数量的数据,并将其存储到指定的内存缓冲区中

        write(destinationFlag, str, size);                 //read()返回实际读取的字节数

    }//write()将指定内存缓冲区中的数据写入到指定文件描述符对应的文件中

    close(sourceFlag);//关闭指定文件描述符对应的文件

    close(destinationFlag);

    printf("System calls:The file.txt copy complete.New file is called CopyFlie1.txt\n");

}

//使用c库函数fopen(),fread(),fwrite(),fclose()

void Copy2() {

    char str[128];

    FILE* sourceFlag, * destinationFlag;

    int size;

    sourceFlag = fopen(source, "r");//读取源文件

    destinationFlag = fopen("/home/pan/CopyFile2.txt", "w");

    if (!sourceFlag) {

        printf("Source file open failed!\n");

        return;

    }

    if (!destinationFlag) {

        printf("Destination file open failed!\n");

        fclose(sourceFlag);

        return;

    }

    //循环读取内容,直到读取到文件结尾

    while ((size = fread(str, sizeof(char), 128, sourceFlag))) {

        fwrite(str, sizeof(char), size, destinationFlag);//从文件开头写 若已存在该文件,则会覆盖。

    }

    fclose(sourceFlag);

    fclose(destinationFlag);

    printf("Library function:The file.txt copy complete.New file is called CopyFlie2.txt\n");

}

int main() {

    Copy1();  //使用系统命令调用

    Copy2();  //使用库函数调用

    return 0;

}

  • 84
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
操作系统实验(含实验报告) 1、进程调度 2、作业调度 3、主存空间的分配与回收 4、文件系统 一、 实验目的 用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。 二、实验内容和要求 编写并调试一个模拟的进程调度程序,采用“简单时间片轮转法”调度算法对五个进程进行调度。 每个进程有一个进程控制块( PCB)表示。进程控制块可以包含如下信息:进程名、到达时间、需要运行时间、已运行时间、进程状态等等。 进程的到达时间及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。 进程的运行时间以时间片为单位进行计算。 每个进程的状态可以是就绪 W(Wait)、运行R(Run)两种状态之一。 就绪进程获得 CPU后都只能运行一个时间片。用运行时间加1来表示。 如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应分配时间片给就绪队列中排在该进程之后的进程,并将它插入就绪队列队尾。 每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。 重复以上过程,直到所要进程都完成为止。 三、实验主要仪器设备和材料 硬件环境:IBM-PC或兼容机 软件环境:C语言编程环境 、实验原理及设计方案 1、进程调度算法:采用多级反馈队列调度算法。其基本思想是:当一个新进程进入内在后,首先将它放入第一个队列的末尾,按FCFS原则排队等待高度。当轮到该进程执行时,如能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚为完成,调度程序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行,以此类推。 2、实验步骤: (1)按先来先服务算法将进程排成就绪队列。 (2)检查所有队列是否为空,若空则退出,否则将队首进程调入执行。 (3)检查该运行进程是否运行完毕,若运行完毕,则撤消进程,否则,将该进程插入到下一个逻辑队列的队尾。 (4)是否再插入新的进程,若是则把它放到第一逻辑队列的列尾。 (5)重复步骤(2)、(3)、(4),直到就绪队列为空。 。。。。。。。。。。。。。。。。。。。。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值