实验一 操作系统系统调用 实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux系统调用实验报告
一、实验目的
深入理解操作系统是虚拟机
二、实验方法
利用UNIX/LINUX所提供的系统调用来编写C语言程序,程序中要体现出一些典型的系统调用(函数)
三、实验任务
编写一个C语言程序,该程序将一个存放了一系列整数的文本文件进行排序,每个整数占据文件的一行,排序的结果存放到一个新的文件之中。源文件和目标文件的文件名由命令行输入。例如:假设可执行文件的文件名是sort,源文件与目标文件的名字分别是data和newdata,那么命令行的情形为如下所示内容:
./sort data newdata
四、实验要点
命令行参数传递、系统调用的使用
五、实验内容
5.1 命令行参数传递
C语言标准规定,C语言程序的入口函数(main 函数)的定义如下:
int main(int argc, char** args)
其中,argc 表示args这个指针数组元素的数量,而args则储存程序的命令行参数,其中,args[0]储存着可执行文件的文件名,args[1]储存第一个命令行参数,如此类推。以在命令行中输入./sort data newdata 为例,args[0]的值为“./sort”,args[1]的值为”data”,args[2]的值为”newdata”。
5.2 打开文件
在操作系统中,需要对一个文件进行读写操作前需要打开文件。open这个系统调用的作用就是打开指定的文件,并返回一个文件描述符。通过这个文件描述符可以对文件进行读写操作。open系统调用的定义如下:
int open(const char* pathname, int flags)
int open(const char* pathname, int flags, mode_t mode)
其中,pathname是要打开文件的路径,flags参数指定文件打开的方式,这个参数可以通过多个常数的位或运算传递多种的方式,其中包括只读(O_RDONLY),只写(O_WRONLY),读写(O_RDWR),创建文件(O_CREAT),追加方式打开(O_APPEND);当使用O_CREAT方式打开文件时,可以通过一个额外的mode参数来控制所创建文件的权限。
mode
在本实验中,一共进行两次的打开操作,分别打开储存有未排序数字以及储存已排序数字的两个文件,打开的代码如下:
int srcFd = open(args[1], O_RDONLY);
if (-1 == srcFd) return -1;
int descFd = open(args[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (-1 == descFd) return -1;
srcFd 表示源文件(储存未排序数据的文件)的文件描述符,O_RDONLY作为flags参数,即表明以只读方式打开。descFd表示目标文件(储存已排序数据的文件)的文件描述符,O_WRONLY | O_CREAT 作为flags参数,表明打开时创建一个文件,并且以只写的方式打开文件,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH作为mode参数,用于指定创建文件的权限,根据上表,这个mode参数创建得到的是一个所有者具有读写权限,组和其他用户具有读权限的文件。
5.3 从文件中把数字读入到内存
read的作用是通过一个文件描述符读取文件中的内容,函数的定义如下:
ssize_t read(int fd, void *buf, size_t count)
fd参数用于指定所读取文件的文件描述符,buf参数则接受一个指针,用于指定储存读出结果的内存空间,count则指定从文件中读取多少个字节。这个系统调用的返回值是从文件中读出的字节数;如果返回0,则表示已经读取到了文件的末尾;如果返回-1,则表示在读取文件的过程中发生错误。
本实验中读取文件的方式是每次读取一个字节,在不断读文件的过程中,对读入的字符进行处理,把文件中的每一个数字储存到一个整型数组之中,下面是读取部分的代码:int num_count = 0, buffer_index = 0, number[1000];
char ch, buffer[30];
while (read(srcFd, &ch, (size_t)1) > 0) {
if (ch >= '0' && ch <= '9') buffer[buffer_index++] = ch;
else if (ch == '\n') {
buffer[buffer_index] = '\0';
buffer_index = 0;
number[num_count++] = atoi(buffer);
}
}
close(srcFd);
读取部分使用一个while循环,循环终止的条件为文件读取完毕或者文件读取过程中发生错误;每次读取1个字节,把读取到的字节储存你1到ch变量之中。因为文件中的每一行储存一个数字,所以换行符就是每个数字之间的间隔符;只要读取到换行符,则表明读取
了一个完整的数字,可以把数字转换成整数并储存到数组之中。如果读取到的不是换行符,而是数字,则把这些数字储存到buffer之中,当读取到换行符时,则把buffer中的数据转换成整数,如此循环,直到把文件中所有的字节读取完成。
读取完成以后,调用close系统调用。这个系统调用是关闭文件描述符,并且释放程序在文件中的锁。对文件操作完成以后关闭文件是个好习惯,需要在不断的练习中养成这个好习惯。
5.4 数据排序
数据从文件中读取到内存以后,以数组的方式储存;对数据进行排序的方法有很多,本实验采用冒泡排序的方式对数组中的数据进行排序。排序的结果仍然储存在原数组
5.5 把排序结果写入到文件之中
跟读取文件一样,向文件写入数据同样需要一个文件描述符;操作系统提供了write这个系统调用,用于用过文件描述符向文件写入数据,write函数的定义如下:ssize_t write(int fd, const void* buf, size_t count);
fd参数指定了写入文件的文件描述符,以buf指针为起点,把buf中的count个字节内容写入到文件之中;如果成功向文件写入内容,则这个系统调用会返回真正写入到文件的字节数;如果这个函数返回0,则表示并没有向文件写入任何内容;如果返回-1,则表示在写入过程中发生了错误。
本实验每次向文件写入一个数字,实验中用于写结果文件的代码如下:
for (i = 0; i < num_count; i++) {
sprintf(buffer, "%d\n", number[i]);
write(descFd, buffer, strlen(buffer));
}
这个代码是一个for循环,循环中一共有两个操作,第一个操作是通过sprintf函数将整数转换为字符串,储存在buffer之中;第二个操作是通过write系统调用,把buffer数组的首地址作为起点,转换得到的字符串长度作为数量,写入到文件中。从而实现写入结果文件的效果。
六、实验结论
计算机本身不具备文件写入和读出功能,这些功能由操作系统提供。操作系统是功能扩展机(虚拟机),它提供了许多系统调用,供程序员使用。