Linux讲解 基础IO-系统调用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Hanani_Jia/article/details/82596313

   上次我们介绍了我们在C语言里边用到的一些IO接口,这些接口是其他人为我们编写好之后提供的,我们还可以通过一些系统的IO,我们要去分清这两个的区别,分清楚什么是系统调用什么是库函数。

可以通过这张图来看一下,这张图通俗来说就是我们的系统调用要比我们的库函数要更加的接近硬件。

系统调用是通向操作系统本身的接口,是面向底层硬件的。通过系统调用,可以使得用户态运行的进程与硬件设备(如CPU、磁盘、打印机等)进行交互,是操作系统留给应用程序的一个接口。下面适用于访问设备驱动程序的系统调用例如:Open:打开一个文件或者设备、Read:从打开的文件或者设备中读取数据、Write:向打开的文件或设备写入数据、Close:关闭一个文件或者设备。用户进程需要发生系统调用时,内核将调用内核相关函数来实现(如sys_read(),sys_write(),sys_fork())。用户程序不能直接调用这些函数,这些函数运行在内核态,CPU 通过软中断切换到内核态开始执行内核系统调用函数。最初我听说系统调用的时候我认为系统函数是更高效更快速的一种调用。实际上使用系统调用会影响系统的性能,在执行调用时的从用户态切换到内核态,再返回用户态会有系统开销。为了减少开销,因此需要减少系统调用的次数,并且让每次系统调用尽可能的完成多的任务。硬件也会限制对底层系统调用一次所能写的数据块的大小。为了给设备和文件提供更高层的接口,Linux系统提供了一系列的标准函数库。使用标准库函数,可以高效的写任意长度的数据块,库函数在数据满足数据块长度要求时安排执行底层系统调用。

一般地,操作系统为了考虑实现的难度和管理的方便,它只提供一少部分的系统调用,这些系统调用一般都是由C和汇编混合编写实现的,其接口用C来定义,而具体的实现则是汇编,这样的好处就是执行效率高,而且,极大的方便了上层调用。

库函数(Library function)是把函数放到库里,供别人使用的一种方式。.方法是把一些常用到的函数编完放到一个文件里,供不同的人进行调用。一般放在.lib文件中。库函数调用则是面向应用开发的,库函数可分为两类,一类是C语言标准规定的库函数,一类是编译器特定的库函数。(由于版权原因,库函数的源代码一般是不可见的,但在头文件中你可以看到它对外的接口)。随着系统提供的这些库函数把系统调用进行封装或者组合,可以实现更多的功能,这样的库函数能够实现一些对内核来说比较复杂的操作。比如,read()函数根据参数,直接就能读文件,而背后隐藏的比如文件在硬盘的哪个磁道,哪个扇区,加载到内存的哪个位置等等这些操作,程序员是不必关心的,这些操作里面自然也包含了系统调用。而对于第三方的库,它其实和系统库一样,只是它直接利用系统调用的可能性要小一些,而是利用系统提供的API接口来实现功能(API的接口是开放的)。部分Libc库中的函数的功能的实现还是借助了系统掉调用,比如printf的实现最终还是调用了write这样的系统调用;而另一些则不会使用系统调用,比如strlen, strcat, memcpy等。 

 这里我们介绍对文件IO的几个系统IO接口,也就是read和write,当然还必须有我们的打开文件和关闭文件open和close。

通过调用系统接口来实现对文件的写入内容

打开我们的myfile文件

同样写入了我们想要写进去的内容。

我们也可以用系统IO去读取我们的文件

这里记着要修改open函数里边的参数

成功输出我们的文件内容。

我们通过man指令来查看我们open函数的使用方法

可以看出来我们的open函数是有两种使用方法的,我们在读写两个程序中也使用了两种,首先pathname就是我们的文件名字,这里传入的是一个指针,flags算是我们打开的一种类型这里主要有以下几种

O_RDONLY          以只读方式打开文件
O_WRONLY         以只写方式打开文件
O_RDWR              以读和写的方式打开文件
上面三个只能选择一个,下面的可以合理的任意组合:
O_CREAT             打开文件,如果文件不存在则建立文件
O_EXCL                如果已经置O_CREAT且文件存在,则强制open()失败
O_TRUNC             将文件的长度截为0
O_APPEND           强制write()从文件尾开始
我们在写文件的时候不仅以只写方式打开,而且我们还加了O_CREAT,这样我们在没有文件的时候会创建一个文件,以防出现错误。

对于open的返回值,如果我们操作成功就会返回新打开的文件描述符,如果失败没有打开就会返回-1. mode_t是我们在没有这个文件去创建文件的时候创建的文件访问权限的初始值。

对于read和write的系统函数调用,man指令都能看的很清楚。

使用man 2 read来查看系统调用的read

这里有三个参数分别是,文件描述符,数组指针,读取的字符。这里就是打开文件描述符所指向的文件,然后读取count的字符放到我们的buf数组中。成功的时候这个函数会返回你所读取到的字符长度,如果失败了会返回-1.

write的函数参数我....这不是和read一样么,只不过这里的buf不再是读取到的数据放进去了,而是把buf中的数据写入到fd指向的文件中,写入长度为count。

这里简单的提一下不知道大家有没有发现,这里的返回值是有负数的,最初我还在纳闷size_t为什么会有负数返回,但是仔细一看是ssize_t大家应该都听过size_t他是一个无符号整型,这是C库里边宏定义,而ssize_t是一个有符号整型,在32位机器上等同与int,在64位机器上等同与long int,size_t 就是无符号型的ssize_t。这里ssize_t和int或者说和long int有什么区别其实这里很难解释,我也没了解透。反正日常看到的话明白他和int是一样是有符号的就行。

 这里对系统的IO进行了一个简单的讲解,这里要明白库函数和系统调用的区别。

 

 

猜你喜欢

转载自blog.csdn.net/Hanani_Jia/article/details/82596313