linux内核read函数,简介⼏种系统调⽤函数:write、read、
open、clos。。。
在 Linux 中,⼀切(或⼏乎⼀切)都是⽂件,因此,⽂件操作在 Linux 中是⼗分重要的,为此,Linux 系统直接提供了⼀些函数⽤于对⽂件和设备进⾏访问和控制,这些函数被称为系统调⽤(syscall),它们也是通向操作系统本⾝的接⼝。
⼀、系统调⽤
系统调⽤就是 Linux 内核提供的⼀组⽤户进程与内核进⾏交互的接⼝。这些接⼝让应⽤程序受限的访问硬件设备,提供了创建新进程并与已有进程进⾏通信的机制,也提供了申请操作系统其他资源的能⼒。
系统调⽤⼯作在内核态,实际上,系统调⽤是⽤户空间访问内核空间的唯⼀⼿段(除异常和陷⼊外,它们是内核唯⼀的合法⼊⼝)。系统调⽤的主要作⽤如下:
1)系统调⽤为⽤户空间提供了⼀种硬件的抽象接⼝,这样,当需要读写⽂件时,应⽤程序就可以不⽤管磁盘类型和介质,甚⾄不⽤去管⽂件所在的⽂件系统到底是哪种类型;
2)系统调⽤保证了系统的稳定和安全。作为硬件设备和应⽤程序之间的中间⼈,内核可以基于权限、⽤户类型和其他⼀些规则对需要进⾏的访问进⾏判断;
3)系统调⽤是实现多任务和虚拟内存的前提。
要访问系统调⽤,通常通过 C 库中定义的函数调⽤来进⾏。它们通常都需要定义零个、⼀个或⼏个参数(输⼊),⽽且可能产⽣⼀些副作⽤(会使系统的状态发⽣某种变化)。系统调⽤还会通过⼀个 long 类型的返回值来表⽰成功或者错误。通常,⽤⼀个负的值来表明错误,0表⽰成功。系统调⽤出现错误时,C 库会把错误码写⼊ errno 全局变量,通过调⽤ perror() 库函数,可以把该变量翻译成⽤户可理解的错误字符串。
⼆、⼏种常⽤的系统调⽤函数
2.1 write 系统调⽤
系统调⽤ write 的作⽤是把缓冲区 buf 的前 nbytes 个字节写⼊与⽂件描述符 fildes 关联的⽂件中。它返回实际写⼊的字节数。如果⽂件描述符有错或者底层的设备驱动程序对数据块长度⽐较敏感,该返回值可能会⼩于 nbytes。如果函数返回值为 0,就表⽰没有写⼊任何数据;如果返回值为 -1,则表明 write 系统调⽤出现了错误,错误代码保存在全局变量 errno ⾥。 write 系统调⽤的原型如下:
#include
size_t write(int fildes,const void *buf,size_t nbytes);
write的返回值其中,size_t 是标准 C 库中定义的⼀个数据类型,实际上就是 unsigned int。
fildes 是⽂件描述符,内核利⽤⽂件描述符来访问⽂件,它是⼀个⾮负的整数,当打开现存⽂件或者新建⼀个⽂件时,都会返回⼀个⽂件描述符。有多少⽂件描述符取决于系统的配置情况,当⼀个程序开始运⾏时,它⼀般有 3 个已经打开的⽂件描述符:标准输⼊ 0;标准输出1;标准错误 2。
#include
#include
#include
int main()
{
size_t x = write(1,"my name is tongye!\n",20);
printf("you have writed %d words to the buffer\n",x);
exit(0);
}
/* 输出结果:
my name is tongye!
you have writed 20 words to the buffer
*/
这段代码简单演⽰了⼀下 write 系统调⽤函数的⽤法:从缓冲区 buffer 中读取前 20 个字节写⼊标准输出中,write 返回了实际写⼊的字节数。
2.2 read 系统调⽤
系统调⽤ read 的作⽤是:从⽂件描述符 fildes 相关联的⽂件⾥读⼊ nbytes 个字节的数据,并把它们放到数据区 buf 中。它返回实际读⼊的字节数,这可能会⼩于请求的字节数。如果 read 调⽤返回 0,就表⽰没有读⼊任何数据,已到达了⽂件尾;如果返回 -1,则表⽰read 调⽤出现了错误。read 系统调⽤的原型如下:
#include
size_t read(int fildes,void *buf,size_t nbytes);
⽤⼀段代码演⽰⼀下⽤法:
#include
#include
#include
int main()
{
char buffer[30];
size_t x = read(0,buffer,30);
write(1,buffer,x);
exit(0);
}
/* 输出结果:
hello ,my name is tongye!
hello ,my name is tongye!
*/
这段代码使⽤ read 系统调⽤函数从标准输⼊读取 30 个字节到缓冲区 buffer 中去(输出结果中的第⼀⾏是从标准输⼊键⼊的),然后使⽤write 系统调⽤函数将 buffer 中的字节写到标准输出中去。
2.3 open 系统调⽤
系统调⽤ open ⽤于创建⼀个新的⽂件描述符。
#include
#include
#include
int open(const char *path,int oflags);
int open(const char *path,int oflags,mode_t mode); // oflags 标志为 O_CREAT 时,使⽤这种格式
open 建⽴了⼀条到⽂件或设备的访问路径。如果调⽤成功,它将返回⼀个可以被 read、write 和其他系统调⽤使⽤的⽂件描述符。这个⽂件描述符是唯⼀的,不会与任何其他运⾏中的进程共享。在调⽤失败时,将返回 -1 并设置全局变量 errno 来指明失败的原因。
使⽤ open 系统调⽤时,准备打开的⽂件或设备的名字作为参数 path 传递给函数,oflags 参数⽤于指定打开⽂件所采取的动作。oflags 参数是通过命令⽂件访问模式与其他可选模式相结合的⽅式来指定的,open 调⽤必须指定以下⽂件访问模式之⼀:
1)O_RDONLY:以只读⽅式打开;
2)O_WRONLY:以只写⽅式打开;
3)O_RDWR :以读写⽅式打开。
另外,还有以下⼏种可选模式的组合( ⽤按位或 || 来操作 ):
4)O_APPEND:把写⼊数据追加在⽂件的末尾;
5)O_TRUNC:把⽂件长度设置为零,丢弃已有的内容;
6)O_CREAT:如果需要,就按照参数 mode 中给出的访问模式创建⽂件;
7)O_EXCL:与 O_CREAT ⼀起使⽤,确保调⽤者创建出⽂件。使⽤这个模式可以防⽌两个程序同时创建同⼀个⽂件,如果⽂件已经存在,open 调⽤将失败。
当使⽤ O_CREAT 标志的 open 调⽤来创建⽂件时,需要使⽤有 3 个参数格式的 open 调⽤。其中,第三个参数 mode 是⼏个标志按位或后得到的,这些标志在头⽂件 sys/stat.h 中定义,如下:
标志
说明
标志
说明
标志
说明
S_IRUSR
⽂件属主可读
S_IRGRP
⽂件所在组可读
S_IROTH
其他⽤户可读
S_IWUSR
⽂件属主可写
S_IWGRP
⽂件所在组可写
S_IWOTH
其他⽤户可写
S_IXUSR
⽂件属主可执⾏
S_IWOTH
⽂件所在组可执⾏
S_IXOTH
其他⽤户可执⾏
⽤⼀个例⼦说明⼀下:
#include
#include
#include
int main()
{
open("file",O_CREAT,S_IRUSR | S_IWGRP);
exit(0);
}
执⾏这段代码将在当前⽬录下创建⼀个名为 file 的⽂件,该⽂件对⽂件属主可读,对⽂件所在组可写,⽤ ls -l 命令查看如下:
可以看到有⼀个名为 file 的⽂件,该⽂件就是使⽤ open 系统调⽤创建的,⽂件的权限为⽂件属主可读,⽂件所在组可写。
2.4 close 系统调⽤
系统调⽤ close 可以⽤来终⽌⽂件描述符 fildes 与其对应⽂件之间的关联。当 close 系统调⽤成功时,返回 0,⽂件描述符被释放并能够重新使⽤;调⽤出错,则返回 -1。
#include
int close(int fildes);
2.5 ioctl 系统调⽤
系统调⽤ ioctl 提供了⼀个⽤于控制设备及其描述符⾏为和配置底层服务的接⼝。终端、⽂件描述符、套接字甚⾄磁带机都可以有为它们定义的 ioctl。
#include
int ioctl(int fildes,int cmd,...);
ioctl 对描述符 fildes 引⽤的对象执⾏ cmd 参数中给出的操作。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论